<?php
/**
 * BugFree is free software under the terms of the FreeBSD License.
 *
 * Module functions library of BugFree system.
 *
 * @link        http://www.bugfree.org.cn
 * @package     BugFree
 */

//------------------------- BASE FUNCTIONS -----------------------------------//
/**
 * Get Current Mode: Bug, Case or Result
 *
 * @author                       Yupeng Lee<leeyupeng@gmail.com>
 */

function baseGetTestMode()
{
    if($_SESSION['TestMode'] == '')
    {
        $_SESSION['TestMode'] = 'Bug';
    }
    return $_SESSION['TestMode'];
}

/*================================User Function Start=================================*/

/**
 * Judge valid user.
 *
 * @global array                  the BugFree config array.
 * @global object                 the object of ADO class created in SetupBug.inc.php.
 * @param  string  $TestUserName  the user name used to login BugFree system.
 * @param  string  $TestUserPWD   the user password used to login BugFree system.
 */
function baseJudgeUser($TestUserName = '',$TestUserPWD = '', $Encrypt = true)
{
    global $_CFG;
    $TestUserName = trim($TestUserName);
    $TestUserPWD = $TestUserPWD;
    $DBName = !empty($_CFG['UserDB']) ? 'MyUserDB' : 'MyDB';

    global $$DBName;


    $TestUserInfo = array();

    if($DBName == 'MyDB')
    {
        $Where = "{$_CFG[UserTable][UserName]} = '" . mysql_real_escape_string($TestUserName) . "'" . " AND IsDroped = '0'";
        $DBTestUserInfo = dbGetRow($_CFG[UserTable][TableName], "{$_CFG[UserTable][UserName]} AS UserName, {$_CFG[UserTable][RealName]} AS RealName, {$_CFG[UserTable][Email]} AS Email, AuthMode",  $Where , $$DBName);
        if(empty($DBTestUserInfo))
        {
             $TestUserInfo = array();
        }
        else
        {
            if($DBTestUserInfo['AuthMode'] == 'LDAP')
            {
                $TestUserInfo = ldapJudgeUser($TestUserName,$TestUserPWD);
                if(!empty($TestUserInfo))
                {
                    $TestUserPWD = baseEncryptUserPWD($TestUserPWD, $TestUserName);
                    
                    if($TestUserInfo['RealName'] == '')
                    {
                        $TestUserInfo['RealName'] = $DBTestUserInfo['RealName'];
                    }
                    if($DBTestUserInfo['Email'] != '')
                    {
                        $TestUserInfo['Email'] = $DBTestUserInfo['Email'];
                    }
                     
                    dbUpdateRow($_CFG['UserTable']['TableName'], 'RealName', "'{$TestUserInfo[RealName]}'"
                                                           , 'UserPassword', "'{$TestUserPWD}'"
                                                           , 'Email', "'{$TestUserInfo[Email]}'"
                                                           , 'LastEditedBy', "'" . mysql_real_escape_string($TestUserInfo['UserName']) . "'"
                                                           , 'LastDate', 'now()'
                                                           , "UserName = '" . mysql_real_escape_string($TestUserName) ."'");
                }
            }
            else
            {
                if($Encrypt)
                {
                    $TestUserPWD = baseEncryptUserPWD($TestUserPWD, $TestUserName);
                }

                $Where = "{$_CFG[UserTable][UserName]} = '" . mysql_real_escape_string($TestUserName) . "' AND {$_CFG[UserTable][UserPassword]} = '{$TestUserPWD}'";
                $TestUserInfo = dbGetRow($_CFG[UserTable][TableName], "{$_CFG[UserTable][UserName]} AS UserName, {$_CFG[UserTable][RealName]} AS RealName, {$_CFG[UserTable][Email]} AS Email"
                                                        ,  $Where , $$DBName);
            }
        }
    }
    else
    {
        if($Encrypt)
        {
            $TestUserPWD = baseEncryptUserPWD($TestUserPWD, $TestUserName);
        }

        $Where = "{$_CFG[UserTable][UserName]} = '" . mysql_real_escape_string($TestUserName) . "' AND {$_CFG[UserTable][UserPassword]} = '{$TestUserPWD}'";
        $TestUserInfo = dbGetRow($_CFG[UserTable][TableName], "{$_CFG[UserTable][UserName]} AS UserName, {$_CFG[UserTable][RealName]} AS RealName, {$_CFG[UserTable][Email]} AS Email"
                                                        ,  $Where , $$DBName);
    }

    return $TestUserInfo;
}


function ldapJudgeUser($TestUserName,$TestUserPWD, $STestUserName = '')
{
    global $_CFG;

    $TestUserInfo = array();

    // LDAP variables
    $ldap['host'] = $_CFG['LDAP']['Host'];
    $ldap['port'] = $_CFG['LDAP']['Port'];
    $ldap['base'] = $_CFG['LDAP']['Base'];

    $ldap['user'] = $TestUserName;
    $ldap['pass'] = $TestUserPWD;
    $ldap['dn'] = $ldap['user'];
   
    if(function_exists('ldap_connect'))
    { 
        // connecting to ldap
        $ldap['conn'] = @ldap_connect( $ldap['host'], $ldap['port'] );
        
        // binding to ldap
        if($ldap['conn'])
        {
            $ldap['bind'] = @ldap_bind($ldap['conn'], $ldap['dn'], $ldap['pass'] );
        
            if($ldap['bind'] )
            {
                if($STestUserName == '')
                {
                    $DomainName = current(explode("\\", $TestUserName));
                    $STestUserName = end(explode("\\", $TestUserName));
                }
                else
                {
                    $DomainName = current(explode("\\", $STestUserName));
                    $STestUserName = end(explode("\\", $STestUserName));
                }
                $ldap['result'] = @ldap_search( $ldap['conn'], $ldap['base'], 'sAMAccountName=' . $STestUserName);
                if($ldap['result'] )
                {
                    // retrieve all the entries from the search result
                    $ldap['info'] = @ldap_get_entries( $ldap['conn'], $ldap['result'] );
                    if( $ldap['info']['count'] >= '1')
                    {
                        foreach($ldap['info'] as $key => $ldap_info)
                        {
                        //$ldap_info = end($ldap['info']);

                       
                        if($domain == $DomainName)
                        {
                            $TestUserInfo['UserName'] = $TestUserName;
                            $TestUserInfo['RealName'] = iconv('gbk','utf-8',$ldap_info['displayname']['0']);
                            $TestUserInfo['Email'] = $ldap_info['mail']['0'];
                            break;
                        }
                        }
                    }
                }
            }
        }
        @ldap_close( $ldap['conn'] );
    }
    return $TestUserInfo;
}

/**
 * Encrypt the password according to the EncryptType defined in Config.inc.php.
 *
 * @author                         Chunsheng Wang <wwccss@263.net>
 * @global  array                  config vars of BugFree system.
 * @param   string  $TestUserPWD   the password before encrypting.
 * @param   string  $TestUserName
 * @return  string                 encrypted password.
 */
function baseEncryptUserPWD($TestUserPWD, $TestUserName = '')
{
    global $_CFG;

    if($_CFG['UserTable']['EncryptType'] == 'md5')
    {
        $TestUserPWD = md5($TestUserPWD);
    }
    elseif($_CFG['UserTable']['EncryptType'] == 'mysqlpassword')
    {
        $TestUserPWD = "PASSWORD('{$TestUserPWD}')";
    }
    elseif($_CFG['UserTable']['EncryptType'] == 'discuzuc')
    {
        $DBName = !empty($_CFG['UserDB']) ? 'MyUserDB' : 'MyDB';
        global $$DBName;
        $TestUserInfo = dbGetRow($_CFG[UserTable][TableName], "{$_CFG[UserTable][UserName]} AS UserName,salt", "UserName = '{$TestUserName}'", $$DBName);
        $TestUserPWD= md5(md5($TestUserPWD).$TestUserInfo['salt']);
    }
    else
    {
        $TestUserPWD = $TestUserPWD;
    }
    return $TestUserPWD;
}

/**
 * Judge User Login Status
 *
 * @author                         Yupeng Lee<leeyupeng@gmail.com>
 */
function baseJudgeUserLogin()
{
    global $_LANG, $_CFG;
    if($_SESSION['TestUserName'] == '')
    {
        if(isset($_COOKIE['BFUser']) && $_COOKIE['BFUser'] != '')
        {
            $mcrypt = new Mcrypt();
            $TestUser = $_COOKIE['BFUser'];
            $TestUser = unserialize($mcrypt->decrypt($TestUser));
            $TestUserName = strtolower($TestUser['BFUserName']);
            $TestUserPWD = $TestUser['BFUserPWD'];
            $TestUserInfo = baseJudgeUser($TestUserName, $TestUserPWD);
            if($TestUserInfo)
            {
                $_SESSION['TestUserACL'] = baseGetUserACL($TestUserInfo['UserName']);
                $_SESSION['TestIsAdmin'] = baseJudgeIsAdmin($TestUserInfo['UserName']);
                if(!$_SESSION['TestIsAdmin'])
                {
                    $_SESSION['TestIsProjectAdmin'] = baseJudgeIsAdmin($TestUserInfo['UserName'], 'ProjectAdmin');
                }
                if(empty($_SESSION['TestUserACL']) && !$_SESSION['TestIsAdmin'])
                {
                    jsAlert(str_replace('<br />', "", $_LANG['Message']['NoPriv']));
                    jsGoTo($_CFG["BaseURL"] . "/Login.php","top");
                    exit;
                }
                else
                {
                    $TestUser['BFUserName'] = $TestUserInfo['UserName'];
                    $TestUser['BFUserPWD']  = $TestUserPWD;
                    @setcookie("BFUser", $mcrypt->encrypt(serialize($TestUser)), time()+1209600,BF_COOKIE_PATH);
                    @setcookie("BFRememberStatus", '1', time()+1209600,BF_COOKIE_PATH);
                    @setcookie("TestCurrentProjectID", $_COOKIE['TestCurrentProjectID'], time()+1209600,BF_COOKIE_PATH);

                    // register session
                    $_SESSION['TestUserName'] = $TestUserInfo['UserName'];
                    $_SESSION['TestUserPWD'] = $TestUserPWD;
                    $_SESSION['TestRealName'] = $TestUserInfo['RealName'];
                    $_SESSION['TestUserEmail'] = $TestUserInfo['Email'];

                    $_SESSION['DomainTestUserName'] = $TestUserInfo['UserName'];
                    $_SESSION['DomainTestUserPWD'] = $TestUserPWD;

                    $_SESSION['TestUserACLSQL'] = 'ProjectID' . dbCreateIN(join(',', array_keys($_SESSION['TestUserACL'])));
                    $TestCurrentProjectID = $_COOKIE['TestCurrentProjectID'] != '' && isset($_SESSION['TestUserACL'][$_COOKIE['TestCurrentProjectID']]) ? $_COOKIE['TestCurrentProjectID'] : key($_SESSION['TestUserACL']);
                    testSetCurrentProject($TestCurrentProjectID);
                }
            }
        }
    }
    else
    {
        return true;
    }
}

/**
 * Judge Adminuser Login Status
 *
 * @author                         Yupeng Lee<leeyupeng@gmail.com>
 *
 */
function baseJudgeAdminUserLogin($AdminLevel = 'SysAdmin,ProjectAdmin')
{
    global $_CFG;
    if(baseJudgeIsAdmin($_SESSION['TestUserName']) && preg_match('/SysAdmin/i', $AdminLevel))
    {
        return true;
    }
    elseif(baseJudgeIsAdmin($_SESSION['TestUserName'], 'ProjectAdmin') && preg_match('/ProjectAdmin/i', $AdminLevel))
    {
        return true;
    }
    else
    {
        sysErrorMsg();
    }
}

/**
 * Judge is admin
 *
 * @author                          Yupeng Lee<leeyupeng@gmail.com>
 * @param  string $UserName         UserName
 * @param  string $AdminType        Admin Type
 * @return bool                     Is admin or not
 *
 */
function baseJudgeIsAdmin($UserName, $AdminType = 'SysAdmin')
{
    global $_CFG;
    $UserName = strtolower($UserName);
    if($AdminType == 'SysAdmin')
    {
        if(in_array($UserName, $_CFG['AdminUser']))
        {
            return true;
        }
    }
    if($AdminType == 'ProjectAdmin')
    {
        $UserName = mysql_real_escape_string($UserName);

        $ProjectList = dbGetList('TestProject', '', "ProjectManagers LIKE '%," . mysql_real_escape_string($UserName) . ",%'");
        if(count($ProjectList) > 0)
        {
            return true;
        }
        $GroupList = dbGetList('TestGroup', '', "AddedBy = '{$UserName}'");
        if(count($GroupList) > 0)
        {
            return true;
        }
        $GroupList = dbGetList('TestGroup', '', "GroupManagers LIKE '%," . mysql_real_escape_string($UserName) . ",%'");
        if(count($GroupList) > 0)
        {
            return true;
        }
    }
    return false;
}


/**
 * Get the User's A C L.
 *
 * @author                         Yupeng Lee <leeyupeng@163.com>
 * @param   string  $TestUserName  UserName.
 * @return  string                 User's ACL.
 */
function baseGetUserACL($TestUserName)
{
    $ProjectList = testGetValidProjectList();
    $UserACL = array();
    $ProjectACL = array();
    $GroupIDList = array();
    $IsAdmin = false;
    if(baseJudgeIsAdmin($TestUserName))
    {
        $IsAdmin = true;
    }
    else
    {
        $GroupACL = testGetGroupList("GroupUser LIKE '%," . mysql_real_escape_string(mysql_real_escape_string($TestUserName)) . ",%'");
        $GroupIDList = array('1' => '1');
        foreach($GroupACL as $GroupInfo)
        {
            $GroupIDList[$GroupInfo['GroupID']] = $GroupInfo['GroupID'];
        }
    }
    foreach($ProjectList as $ProjectID => $ProjectInfo)
    {
        if($IsAdmin)
        {
            $UserACL[$ProjectID] = 'All';
        }
        elseif(array_intersect($ProjectInfo['ProjectGroupList'], $GroupIDList))
        {
            $UserACL[$ProjectID] = 'All';
        }
    }
    return $UserACL;
}


/**
 * Get query string from group query post in SearchBug.php/SearchCase.php/SearchResult.php
 *
 * @author                          Yupeng Lee<leeyupeng@gmail.com>
 * @param  array   $PostQueryArray  Query array posted from BugSearchForm, CaseSearchForm or ResultSearchForm
 * @return string                   Query string for SQL
 */
function baseGetFieldListStr($PostQueryArray)
{
    global $_CFG;
    $FieldListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $FieldListStr[] = $PostQueryArray['Field'.$I];
    }
    return $FieldListStr;
}

function baseGetValueListStr($PostQueryArray)
{
    global $_CFG;
    $ValueListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $ValueListStr[] = $PostQueryArray['Value'.$I];
    }
    return $ValueListStr;
}

function baseGetOperatorListStr($PostQueryArray)
{
    global $_CFG;
    $OperatorListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $OperatorListStr[] = $PostQueryArray['Operator'.$I];
    }
    return $OperatorListStr;
}

function baseGetLeftParentheseListStr($PostQueryArray)
{
    global $_CFG;
    $LeftParentheseListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $LeftParentheseListStr[] = $PostQueryArray['LeftParenthesesName'.$I];
    }
    return $LeftParentheseListStr;
}
function baseGetRightParentheseListStr($PostQueryArray)
{
    global $_CFG;
    $RightParentheseListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $RightParentheseListStr[] = $PostQueryArray['RightParenthesesName'.$I];
    }
    return $RightParentheseListStr;
}


function baseGetAndOrListStr($PostQueryArray)
{
    global $_CFG;
    $AndOrListStr = array();
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    for ($m = 0; $m < count($queryOrderIndexArr); $m++) {
        $I = $queryOrderIndexArr[$m];
        $AndOrListStr[] = $PostQueryArray['AndOr'.$I];
    }
    return $AndOrListStr;
}
function getQueryOrder($QueryRowOrderStr)
{
    $arr = explode(",",$QueryRowOrderStr);
    $indexArr = array();
    for($i = 0;$i<count($arr);$i++)
    {
        if("" != trim($arr[$i]))
        {
            $indexArr[] = str_replace('SearchConditionRow', '', $arr[$i]);
        }
    }
    return $indexArr;
}
function baseGetGroupQueryStr($PostQueryArray)
{

    global $_CFG;
    $FirstQueryGroup = array();
    $SecondQureyGroup = array();

    $FieldName = 'Field';
    $OperatorName = 'Operator';
    $ValueName = 'Value';
    $AndOrName = 'AndOr';
    $LeftParenthesesName = 'LeftParenthesesName';
    $RightParenthesesName = 'RightParenthesesName';
    $QueryFieldCountName = 'QueryFieldCount';
    $QueryRowOrderStr = $PostQueryArray['QueryRowOrder'];
    $queryOrderIndexArr = getQueryOrder($QueryRowOrderStr);
    $orderIndexCount = count($queryOrderIndexArr);
    for ($m = 0; $m < $orderIndexCount; $m++) {
        $I = $queryOrderIndexArr[$m];
        $WhereStr = ' ';
        $TempQueryStr = baseGetFieldQueryStr($PostQueryArray[$FieldName . $I], $PostQueryArray[$OperatorName . $I], $PostQueryArray[$ValueName . $I]);
        if ($TempQueryStr == '') {
            if ($PostQueryArray[$LeftParenthesesName . $I] == "(" && $PostQueryArray[$RightParenthesesName . $I] == ")")
            {
                
            }
            else if ($PostQueryArray[$LeftParenthesesName . $I] == "(")
            {
                $WhereStr = "(";
                $QueryGroup[] = $WhereStr;
            } 
            else if ($PostQueryArray[$RightParenthesesName . $I] == ")")
            {
                $WhereStr = ")";
                if (ucfirst($PostQueryArray[$AndOrName . $I]) == 'And') {
                    $WhereStr = $WhereStr . ' AND ';
                } elseif (ucfirst($PostQueryArray[$AndOrName . $I]) == 'Or') {
                    $WhereStr = $WhereStr . ' OR  ';
                }

                $preCondition = $QueryGroup[count($QueryGroup)-1];
                if("(" == $preCondition)
                {
                    array_pop($QueryGroup);
                }
                else
                {
                    $preCondition = substr($preCondition, 0, strlen($preCondition)-strlen(" AND "));
                    $QueryGroup[count($QueryGroup)-1] = $preCondition." ".$WhereStr;
                }
                
                //$QueryGroup[] = $WhereStr;
            }
        } else {
            $WhereStr = $TempQueryStr;
            if ($PostQueryArray[$LeftParenthesesName . $I] == "(") {
                $WhereStr = "(" . $WhereStr;
            }
            if ($PostQueryArray[$RightParenthesesName . $I] == ")") {
                $WhereStr = $WhereStr . ")";
            }

            if (ucfirst($PostQueryArray[$AndOrName . $I]) == 'And') {
                $WhereStr = $WhereStr . ' AND ';
            } elseif (ucfirst($PostQueryArray[$AndOrName . $I]) == 'Or') {
                $WhereStr = $WhereStr . ' OR  ';
            }
            $QueryGroup[] = $WhereStr;
        }
    }

    if($QueryGroup == null)
    {
        return "";
    }
    else
    {
        $ResultQueryStr = join(' ', $QueryGroup);
        $ResultQueryStr = "(".substr($ResultQueryStr, 0, strlen($ResultQueryStr)-strlen(" AND ")).")";
        return $ResultQueryStr;
    }
    
}

/**
 * Get query string with one field
 *
 * @author                          Yupeng Lee<leeyupeng@gmail.com>
 * @param  string  $FieldName       FieldName
 * @param  string  $OperatorName    =,<,>,<= eg.
 * @param  string  $FieldValue      FieldValue
 * @return string                   Query string for SQL
 */
function baseGetFieldQueryStr($FieldName, $OperatorName, $FieldValue)
{
   global $_LANG;

   if(preg_match('/Date/',$FieldName))
   {//选择了日期相关的查询条件
       $FieldValue = trim($FieldValue);
        if($FieldValue!="" && !preg_match('/^-?[1-9]\d*$|^0$|^(19|20)\d{2}-(0?\d|1[012])-(0?\d|[12]\d|3[01])$/', $FieldValue))
        {
            jsAlert($_LANG['DateInvalidAlert']);
            jsGoTo($_SESSION['TestMode'] .'List.php',"parent.RightBottomFrame");
            exit;
        }
        if(preg_match('/^-?[1-9]\d*$|^0$/', $FieldValue))
        {//如果输入为整数，则进行日期的换算
            $FieldValue = date( "Y-m-d", mktime(0,0,0,date("m") ,date("d")+$FieldValue,date("Y")));
        }

    }
    if (preg_match('/^OpenedBy$|^ResolvedBy$|^ClosedBy$|^LastEditedBy$|^ModifiedBy$|^MailTo$/', $FieldName) && $OperatorName=='IN'&&$FieldValue!="")
    {
       $FieldValue = preg_replace('/^,*|,*$/','',trim($FieldValue));
       $FieldValue = preg_replace('/,,*/',',',$FieldValue);
       $FieldValue = preg_replace('/,/',"','",$FieldValue);
       $FieldValue = "'" . $FieldValue . "'";
    }


    if(preg_match('/Title$/', $FieldName))
    {
        $FieldValue = htmlspecialchars($FieldValue);
    }

    $QueryStr = '';
    if($FieldValue == '')
    {
        return $QueryStr;
    }

    if(ucfirst($FieldValue) == 'Null')
    {
        $FieldValue = '';
    }

    if($OperatorName == 'LIKE')
    {
        $QueryStr = "LIKE '%{$FieldValue}%' ";
    }
    elseif($OperatorName == 'NOT LIKE')
    {
        $QueryStr = "NOT LIKE '%{$FieldValue}%' ";
    }
    elseif($OperatorName == 'UNDER')
    {
        if(preg_match('/^\//', $FieldValue))
        {
        $QueryStr = "LIKE '{$FieldValue}%' ";
    }
        else
        {
            $QueryStr = "LIKE '/{$FieldValue}%' ";
        }
    }
    elseif($OperatorName == '!=')
    {
        if('ModifiedBy' == $FieldName)
        {
            $QueryStr = "NOT LIKE '%," . mysql_real_escape_string($FieldValue) . ",%' ";
        }
        else
        {
            $QueryStr = "NOT " . dbCreateIN($FieldValue) . " ";
        }
        if(preg_match('/date/i', $FieldName))
        {
             $QueryStr ="NOT " . sysStrToDateSql($FieldValue);
        }
    }
    elseif($OperatorName == '=')
    {
        if(preg_match('/date/i', $FieldName))
        {
            $QueryStr = sysStrToDateSql($FieldValue);

        }
        elseif('ModifiedBy' == $FieldName || 'MailTo' == $FieldName)
        {
            $QueryStr = "LIKE '%" . mysql_real_escape_string($FieldValue) . "%' ";
        }
        else
        {
            $QueryStr = $OperatorName . " '{$FieldValue}' ";
        }
    }
    elseif($OperatorName == 'IN')
    {
         $QueryStr = "IN ({$FieldValue}) ";

    }
    else
    {
        if(($OperatorName == '>' || $OperatorName == '<=') && preg_match('/date/i', $FieldName))
        {
           $DateTimeArray =  explode(" ", sysStrToDateSql($FieldValue));
           $FieldValue = $DateTimeArray[4] . ' ' . $DateTimeArray[5];
           $QueryStr = $OperatorName . " {$FieldValue} ";
        }
        elseif( ($OperatorName == '>=' || $OperatorName == '<') && preg_match('/date/i', $FieldName))
        {
           $DateTimeArray =  explode(" ", sysStrToDateSql($FieldValue));
           $FieldValue = $DateTimeArray[1] . ' ' . $DateTimeArray[2];
           $QueryStr = $OperatorName . " {$FieldValue} ";
        }
        else
        {
           $QueryStr = $OperatorName . " '{$FieldValue}' ";
        }
    }

    $QueryStr = $FieldName . ' ' . $QueryStr;
    return $QueryStr;
}

/**
 * Compare the PreAppendName in array
 *
 * @author                          Yupeng Lee<leeyupeng@gmail.com>
 * @param  array   $a               array a
 * @param  array   $b               array b
 * @return bool                     equal or not
 */
function testCmpPreAppendName($a, $b)
{
    global $_CFG;
    if(is_array($a) && is_array($b))
    {
        return strcmp(strtoupper($a['PreAppendName']), strtoupper($b['PreAppendName']));
    }
    else
    {
        return strcmp($a, $b);
    }
}

/**
 * Get user list which are not droped
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 * @param  string  $Where    SQL condition
 * @param  string  $OrderyBy SQL order by
 * @param  string  $Limit    SQL limit: m, n
 * @param  string  $ListKey  the key of result array
 * @return array             UserList
 */
function testGetUserList($Where = '', $OrderBy = 'UserName ASC', $Limit = '', $ListKey = 'UserName')
{
    global $_CFG;

    $DBName = !empty($_CFG['UserDB']) ? 'MyUserDB' : 'MyDB';
    global $$DBName;

    global $_CFG;

    $Columns = "{$_CFG[UserTable][UserName]} AS UserName, {$_CFG[UserTable][RealName]} AS RealName, {$_CFG[UserTable][RealName]} AS PreAppendName, {$_CFG[UserTable][UserPassword]} AS UserPassword, {$_CFG[UserTable][Email]} AS Email, {$_CFG[UserTable][NoticeFlag]} AS NoticeFlag";
    $Columns = !empty($_CFG['UserDB']) ? $Columns : 'UserID, ' . $Columns;
    if($Where != "")
    {
        $Where = !empty($_CFG['UserDB']) ? $Where : $Where . " AND IsDroped = '0'";
    }
    else
    {
        $Where = !empty($_CFG['UserDB']) ? $Where : "IsDroped = '0'";
    }

    $UserList = dbGetList($_CFG['UserTable']['TableName'], $Columns, $Where, '', $OrderBy, $Limit, 'UserName', $$DBName, $ListKey);
    $DuplicateRealName = array();
    foreach($UserList as $UserName => $UserInfo)
    {
        $DuplicateRealName[$UserName] = $UserInfo['RealName'];
    }
    $CountDuplicateRealName = array_count_values($DuplicateRealName);
    foreach($UserList as $UserName => $UserInfo)
    {
        $PreAppendName = sysPinYinStr($UserInfo['RealName']);
        if($PreAppendName != '')
        {
            $UserList[$UserName]['PreAppendName'] = $PreAppendName . " " . $UserInfo['RealName'];
        }
        if($CountDuplicateRealName[$UserInfo['RealName']] > 1)
        {
            $UserList[$UserName]['PreAppendName'] = $UserList[$UserName]['PreAppendName'] . "[{$UserName}]";
        }
        $UserList[$UserName]['Wangwang']   = $UserInfo['Wangwang'];
        $UserList[$UserName]['NoticeFlag'] = $UserInfo['NoticeFlag'];
    }

    return $UserList;
}

/**
 * Get user list which are not droped
 *
 * @author                       Yupeng Lee<leeyupeng@gmail.com>
 * @param  string  $Where        SQL condition
 * @param  string  $OrderyBy     SQL order by
 * @param  string  $Limit        SQL limit: m, n
 * @param  string  $ListKey      the key of result array
 * @param  string  $ListValue    the value of result array
 * @return array   $TestUserList UserList
 */
function testGetOneDimUserList($Where = '', $OrderBy = 'RealName ASC', $Limit = '', $ListKey = 'UserName', $ListValue= 'RealName')
{
    $TempUserList = testGetUserList($Where, $OrderBy, $Limit, $ListKey);
    $TestUserList = array();
    foreach($TempUserList as $UserInfo)
    {
        $TestUserList[$UserInfo[$ListKey]] = $UserInfo[$ListValue];
    }
    return $TestUserList;
}

/**
 * Get user list which are not droped
 *
 * @author              Yupeng Lee<leeyupeng@gmail.com>
 * @param  string  $Where        SQL condition
 * @param  string  $OrderyBy     SQL order by
 * @param  string  $Limit        SQL limit: m, n
 * @return array   $TestUserList UserList
 */
function testGetAllUserList($Where = '', $OrderBy = '', $Limit = '')
{
    global $_CFG;

    $DBName = !empty($_CFG['UserDB']) ? 'MyUserDB' : 'MyDB';
    global $$DBName;

    $Columns = "{$_CFG[UserTable][UserName]} AS UserName, CONCAT(UPPER(LEFT({$_CFG[UserTable][UserName]},1)),': ',{$_CFG[UserTable][RealName]}) AS PreAppendName, {$_CFG[UserTable][RealName]} AS RealName, {$_CFG[UserTable][Email]} AS Email";
    $Columns = !empty($_CFG['UserDB']) ? $Columns : 'UserID, AddedBy, AddDate, LastEditedBy, LastDate, IsDroped, AuthMode, ' . $Columns;
    return dbGetList($_CFG['UserTable']['TableName'], $Columns, $Where, '', $OrderBy, $Limit, 'UserName', $$DBName);
}

/**
 * Get user info by username
 *
 * @author                    Yupeng Lee<leeyupeng@gmail.com>
 * @param    string $UserName
 * @return   array  $UserInfo
 */
function testGetUserInfoByName($UserName)
{
    global $_CFG;
    $UserInfo = array_pop(testGetUserList("{$_CFG[UserTable][UserName]}='{$UserName}'"));
    return $UserInfo;
}

/*======================================User Functions End====================================*/


/**
 * Set current bug tab
 *
 * @author              Yupeng Lee<leeyupeng@gmail.com>
 */
function testSetCurrentBugTab($TabNum)
{
    $_SESSION['TestCurrentBugTabNum'] = $TabNum;
    @setcookie('TestCurrentBugTabNum', $TabNum, time()+1209600,BF_COOKIE_PATH);
}

function testGetCurrentTabNum($hasCookie = false)
{
    $TabNum = 0;
    if($hasCookie)
    {
        if(isset($_COOKIE['TestCurrentBugTabNum']))
        {
            $TabNum = $_COOKIE['TestCurrentBugTabNum'];
        }
    }
    if(isset($_SESSION['TestCurrentBugTabNum']))
    {
        $TabNum = $_SESSION['TestCurrentBugTabNum'];
    }

    if($TabNum != null)
    {
        testSetCurrentBugTab($TabNum);
    }
    return $TabNum;
}

/*=======================================Project Functions Start==============================*/
/**
 * Set current project
 *
 * @author              Yupeng Lee<leeyupeng@gmail.com>
 */
function testSetCurrentProject($ProjectID)
{
    $_SESSION['TestCurrentProjectID'] = $ProjectID;
    @setcookie('TestCurrentProjectID', $ProjectID, time()+1209600,BF_COOKIE_PATH);
}

function testGetCurrentProjectId($hasCookie = false, $ProjectKey = 'ProjectID')
{
    $projectId = null;
    if($hasCookie)
    {
        if(isset($_COOKIE['TestCurrentProjectID']))
        {
            $projectId = $_COOKIE['TestCurrentProjectID'];
        }
    }
    if(isset($_SESSION['TestCurrentProjectID']))
    {
        $projectId = $_SESSION['TestCurrentProjectID'];
    }
    if(isset($_REQUEST[$ProjectKey]))
    {
        $projectId = $_REQUEST[$ProjectKey];
    }
    if($projectId != null)
    {
        testSetCurrentProject($projectId);
    }
    return $projectId;
}

/**
 * Get project list
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 * @param  string  $Where     SQL condition
 * @param  string  $OrderyBy  SQL ordery by
 * @param  string  $Limit     SQL limit
 * @return array              ProjectList
 */
function testGetProjectList($Where = '', $OrderBy = '', $Limit = '')
{
    $ProjectList = dbGetAllColumns('TestProject', $Where, '', $OrderBy, $Limit, 'ProjectID');
    foreach($ProjectList as $ProjectID => $ProjectInfo)
    {
        $ProjectList[$ProjectID]['ProjectManagerList'] = sysTrimExplode(',', $ProjectInfo['ProjectManagers']);
        $ProjectList[$ProjectID]['ProjectGroupList'] = sysTrimExplode(',', $ProjectInfo['ProjectGroupIDs']);
    }
    return $ProjectList;
}


/**
 * Get projects which aren't dropped
 *
 * @author              Yupeng Lee<leeyupeng@gmail.com>
 * @param   string  $Where  SQL condition
 * @return  array           Valid ProjectList
 */
function testGetValidProjectList($Where = '')
{
    $WhereIsNotDropped = "IsDroped = '0'";
    if($Where == '')
    {
        $Where = $WhereIsNotDropped;
    }
    else
    {
        $Where .= ' AND ' . $WhereIsNotDropped;
    }

    $OrderBy = 'DisplayOrder DESC';

    return testGetProjectList($Where, $OrderBy);
}

/**
 * Get project(not dropped) list's select html
 *
 * @author                             Yupeng Lee<leeyupeng@gmail.com>
 * @param   array  $ProjectListName
 * @param   int    $ProjectIDSelected  Slelected in select html
 * @param   string $Attrib             Html attrib
 * @return  string                     Html code
 */
function testGetValidProjectSelectList($ProjectListName, $ProjectIDSelected = '', $Attrib)
{
    $ProjectList = testGetValidProjectList($_SESSION['TestUserACLSQL']);
    $ProjectListSelect = htmlSelect($ProjectList, $ProjectListName, '', $ProjectIDSelected, $Attrib, 'ProjectID,ProjectName');
    return $ProjectListSelect;
}

/**
 * Get all project list's select html
 *
 * @author                             Yupeng Lee<leeyupeng@gmail.com>
 * @param   array  $ProjectListName
 * @param   int    $ProjectIDSelected  Slelected in select html
 * @param   string $Attrib             Html attrib
 * @return  string                     Html code
 */
function testGetAllProjectSelectList($ProjectListName, $ProjectIDSelected = '', $Attrib)
{
    if($ProjectIDSelected == '')
    {
        $ProjectID = $_SESSION['TestCurrentProjectID'];
    }
    $OrderBy = 'DisplayOrder DESC';
    $ProjectList = testGetProjectList('', $OrderBy);
    $ProjectListSelect = htmlSelect($ProjectList, $ProjectListName, '', $ProjectIDSelected, $Attrib, 'ProjectID,ProjectName');
    return $ProjectListSelect;
}

/**
 * Get project(not dropped) array, key:ProjectID value:ProjectName
 *
 * @author                             Yupeng Lee<leeyupeng@gmail.com>
 * @param   array  $Where              SQL condition
 * @return  array                      Project array
 */
function testGetValidSimpleProjectList($Where = '')
{
    $ProjectList = testGetValidProjectList($_SESSION['TestUserACLSQL']);
    $SimpleProjectList = array();
    foreach($ProjectList as $Key => $Value)
    {
        $SimpleProjectList[$Value['ProjectID']] = $Value['ProjectName'];
    }
    return $SimpleProjectList;
}

/**
 * Get UserList by ProjectID
 *
 * @author                           Yupeng Lee <leeyupeng@gmail.com>
 * @param   string  $ProjectIDs      ProjectID split by ,
 * @param   bool    $ContainNullUser Return array whith ''=>'' or not
 * @return  array
 */
function testGetProjectUserList($ProjectIDs, $ContainNullUser = false)
{
    $GroupList = testGetGroupList();
    $ProjectList = testGetProjectList('ProjectID ' . dbCreateIn($ProjectIDs));
    $ProjectUserList = array();

    foreach($ProjectList as $ProjectID => $ProjectInfo)
    {
        $GroupIDList = sysTrimExplode(',', $ProjectInfo['ProjectGroupIDs']);
        foreach($GroupIDList as $GroupID)
        {
            if(is_array($GroupList[$GroupID]['GroupUserList']))
            {
                $ProjectUserList += $GroupList[$GroupID]['GroupUserList'];
            }
        }
    }

    $UserCountList = @array_count_values($ProjectUserList);
    if(!is_array($UserCountList)) $UserCountList = array();
    foreach($ProjectUserList as $UserName => $RealName)
    {
        if($RealName == '')
        {
            $RealName = $UserName;
        }
        $LastRealName = $RealName;

        if($UserCountList[$RealName] > 1)
        {
            $LastRealName .= "[{$UserName}]";
        }
       $ProjectUserList[$UserName] = $LastRealName;
    }
    natcasesort($ProjectUserList);
    if($ContainNullUser)
    {
        $ProjectUserList = array(''=>'') + $ProjectUserList;
    }

    return $ProjectUserList;
}

/**
 * Get UserNameList by ProjectID
 *
 * @author                           Yupeng Lee <leeyupeng@gmail.com>
 * @param   string  $ProjectIDs      ProjectID split by ,
 * @param   bool    $ContainNullUser Return array whith ''=>'' or not
 * @return  array
 */
function testGetProjectUserNameList($ProjectIDs, $ContainNullUser = false)
{
    $GroupList = testGetGroupList();
    $ProjectList = testGetProjectList('ProjectID ' . dbCreateIn($ProjectIDs));
    $ProjectUserList = array();

    foreach($ProjectList as $ProjectID => $ProjectInfo)
    {
        $GroupIDList = sysTrimExplode(',', $ProjectInfo['ProjectGroupIDs']);
        foreach($GroupIDList as $GroupID)
        {
            if(is_array($GroupList[$GroupID]['GroupUserNameList']))
            {
                $ProjectUserList += $GroupList[$GroupID]['GroupUserNameList'];
            }
        }
    }
    natcasesort($ProjectUserList);
    if($ContainNullUser)
    {
        $ProjectUserList = array(''=>'') + $ProjectUserList;
    }

    return $ProjectUserList;
}

/**
 * Get current usernamelist who have the rights in $_SESSION['TestUserACL']
 *
 * @author                       Yupeng Lee <leeyupeng@gmail.com>
 * @param   bool  $PreAppend
 * @return  arary
 */
function testGetCurrentUserNameList($PreAppend = false)
{
    if($PreAppend)
    {
        return testGetProjectUserList(join(',',array_keys($_SESSION['TestUserACL'])));
    }
    return testGetProjectUserNameList(join(',',array_keys($_SESSION['TestUserACL'])));
}
/*=======================================Project Functions End==============================*/


/*=======================================Module Functions Start===============================*/

/**
 * Get module list
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ProjectID
 * @param   string $ModuleType Bug or Case
 * @return  array  $ModuleList
 */
function testGetModuleList($ProjectID, $ModuleType = 'Bug')
{
    $Where = "ProjectID = '{$ProjectID}' ";
    $Where .= "AND ModuleType = '{$ModuleType}' ";
    $OrderBy = "ModuleGrade DESC, DisplayOrder ASC, ModuleID DESC";

    $ModuleList = dbGetAllColumns('TestModule', $Where, '', $OrderBy, '', 'ModuleID');

    $TreeModuleList = array(0=>array());
    foreach($ModuleList as $ModuleID => $ModuleInfo)
    {
        $ParentID = $ModuleInfo['ParentID'];
        $ModuleInfo['ChildIDs'] =  $ModuleID;

        if(!isset($TreeModuleList[$ParentID]))
        {
            $TreeModuleList[$ParentID] = array();
        }
        if(!isset($TreeModuleList[$ModuleID]))
        {
            $TreeModuleList[$ParentID] = array($ModuleID => $ModuleInfo) + $TreeModuleList[$ParentID];
        }
        else
        {
            $ModuleInfo['ChildIDs'] .= ',' . join(',', array_keys($TreeModuleList[$ModuleID]));
            $TreeModuleList[$ParentID] = array($ModuleID => $ModuleInfo) + $TreeModuleList[$ModuleID] + $TreeModuleList[$ParentID];
            unset($TreeModuleList[$ModuleID]);
        }
    }

    return $TreeModuleList[0];
}


/**
 * Get project module List, including the root module '/'
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ProjectID
 * @param   string $ModuleType  Bug or Case
 * @return  array  $ModuleList
 */
function testGetProjectModuleList($ProjectID, $ModuleType = 'Bug')
{
    $ProjectInfo = array_pop(testGetProjectList("ProjectID = '{$ProjectID}'"));
    if($ModuleType == 'Result')
    {
        $ModuleType = 'Case';
    }

    $ParentID = '0';
    $LastModuleID = '0';
    $ModuleList = array('0' => array('ModuleID' => 0,
                        'ParentID' => '',
                        'ModuleName' => $ProjectInfo['ProjectName'],
                        'IDPathe' => '0',
                        'NamePath' => '/',
                        'IsLeaf' => true,
                        'IsLastLeaf' => true,
                        'ModuleGrade' => '0',
                        'ChildIDs' => '0'));

    $ProjectModuleList = testGetModuleList($ProjectID, $ModuleType);
    $ModuleList += $ProjectModuleList;
    foreach($ModuleList as $ModuleID => $ModuleInfo)
    {
        if($ModuleID == '0')
        {
            continue;
        }
        $ModuleList[$ModuleID]['IsLastLeaf'] = true;

        if($ParentID == $ModuleInfo['ParentID'])
        {
            $ModuleList[$LastModuleID]['IsLastLeaf'] = false;
        }

        $ParentID = $ModuleInfo['ParentID'];


        $ParentIDPath = $ModuleList[$ParentID]['IDPath'];
        $ParentNamePath = $ModuleList[$ParentID]['NamePath'];
        if($ParentIDPath == '')
        {
            $ParentIDPath = '0';
        }
        $ModuleList[$ModuleID]['IDPath'] = $ParentIDPath . ',' . $ModuleID;
        if($ParentNamePath == '/')
        {
            $ParentNamePath = '';
        }
        $ModuleList[$ModuleID]['NamePath'] = $ParentNamePath . '/' . $ModuleInfo['ModuleName'];
        $ModuleList[$ModuleID]['IsLeaf'] = true;
        if($ParentID != '')
        {
            $ModuleList[$ParentID]['IsLeaf'] = false;
            $ModuleList[$ParentID]['IsLastLeaf'] = false;
        }

        $ModuleList[$LastModuleID]['NextTreeModuleID'] = $ModuleID;
        $LastModuleID = $ModuleID;
    }

    return $ModuleList;
}

/**
 * Get project module tree menu html code
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ProjectID
 * @param   string $LinkUrl
 * @param   string $ModuleType  Bug or Case
 * @return  string
 */
function testGetTreeModuleList($ProjectID, $LinkUrl = '', $ModuleType = 'Bug')
{
    $ModuleList = testGetProjectModuleList($ProjectID, $ModuleType);

    $TreeMenuHtml = "<ul id='Tree_{$ProjectID}'>";
    foreach($ModuleList as $ModuleID => $ModuleInfo)
    {
        if($ModuleInfo['ModuleGrade'] - 0 < 1)
        {
            $TreeMenuHtml .= '<li class="OpenedNode">';
        }
        else
        {
            $TreeMenuHtml .= '<li>';
        }
        $TreeMenuHtml .=  "<a id='Child_{$ProjectID}_{$ModuleID}' title='{$ModuleInfo[ModuleName]}#$ModuleID' href='javascript:;' onclick='parent.RightTopFrame.location=\"Search{$ModuleType}.php?reset=1&ProjectID={$ProjectID}\";parent.RightBottomFrame.location=\"{$LinkUrl}ProjectID={$ProjectID}&ModuleID={$ModuleID}&ChildModuleIDs={$ModuleInfo['ChildIDs']}\";treeMenuChildAction(\"Tree_{$ProjectID}\",\"Child_{$ProjectID}_{$ModuleID}\");return false;'>{$ModuleInfo[ModuleName]}</a>";
        if($ModuleInfo['IsLeaf'])
        {
            if($ModuleInfo['IsLastLeaf'])
            {
                $TreeMenuHtml .= str_repeat('</li></ul>', abs($ModuleInfo['ModuleGrade'] - $ModuleList[$ModuleInfo['NextTreeModuleID']]['ModuleGrade'] ));
            }
            else
            {
                $TreeMenuHtml .= '</li>';
            }
        }
        else
        {
            $TreeMenuHtml .= '<ul>';
        }
    }
    return $TreeMenuHtml;
}

/**
 * Get module list's select html
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ProjectID
 * @param   string $LinkUrl
 * @param   string $ModuleType  Bug or Case
 * @return  string
 */
function testGetSelectModuleList($ProjectID, $ModuleListName, $ModuleSelected = '', $Attrib ='', $ModuleType = 'Bug')
{
    $ModuleList = testGetProjectModuleList($ProjectID, $ModuleType);
    $ModuleIDSelected = '0';
    if(!empty($ModuleList[$ModuleSelected]))
    {
        $ModuleIDSelected = $ModuleSelected;
    }
    else
    {
        foreach($ModuleList as $ModuleID => $ModuleInfo)
        {
            if($ModuleInfo['ModuleName'] == $ModuleSelected)
            {
                $ModuleIDSelected = $ModuleID;
                break;
            }
        }
    }
    $ModuleSelectList = htmlSelect($ModuleList, $ModuleListName, '', $ModuleIDSelected, $Attrib, 'ModuleID,NamePath');
    return $ModuleSelectList;
}

/**
 * Get module info by moduleid
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param   int   $ModuleID
 * @return  array $ModuleInfo
 */
function testGetModuleInfo($ModuleID)
{
    $ModuleInfo = array_pop(dbGetAllColumns('TestModule', "ModuleID = '{$ModuleID}'"));

    if(empty($ModuleInfo))
    {
        $ModuleInfo['ModuleOwner'] = '';
    }
    return $ModuleInfo;
}

/**
 * Get module path by moduleid
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ModuleID
 * @return  string $ModulePath
 */
function testGetModulePath($ModuleID)
{
    if($ModuleID - 0 == 0)
    {
        return '/';
    }

    $ModuleInfo = testGetModuleInfo($ModuleID);
    $ModulePathArr[] = $ModuleInfo['ModuleName'];
    while($ModuleInfo['ModuleGrade']>1)
    {
        $ModuleInfo = testGetModuleInfo($ModuleInfo['ParentID']);
        $ModulePathArr[] = $ModuleInfo['ModuleName'];
    }
    return '/' . join('/', array_reverse($ModulePathArr));
}
/*=======================================Module Functions End===============================*/

/*=======================================Group Functions Start==============================*/

/**
 * Get group list
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 * @param   string $Where    SQL condition
 * @param   string $OrderyBy SQL order by
 * @param   string $Limit    SQL limit m,n
 * @return  array  $GroupList
 */
function testGetGroupList($Where = '', $OrderBy = '', $Limit = '')
{
    $GroupList = dbGetAllColumns('TestGroup', $Where, '', $OrderBy, $Limit, 'GroupID');
    $UserList = testGetUserList();

    foreach($GroupList as $Key => $GroupInfo)
    {
        $GroupUserList = explode(',', $GroupInfo['GroupUser']);
        $GroupList[$Key]['GroupUserList'] = array();
        $GroupList[$Key]['GroupUserNameList'] = array();

        $GroupManagerList = explode(',', $GroupInfo['GroupManagers']);
        $GroupList[$Key]['GroupManagerList'] = array();
        $GroupList[$Key]['GroupManagerNameList'] = array();
        if($GroupInfo['GroupID'] == '1')
        {
            foreach($UserList as $UserName => $UserInfo)
            {
                $LastRealName = $UserInfo['PreAppendName'];
                $GroupList[$Key]['GroupUserList'][$UserName] = $LastRealName;
                $GroupList[$Key]['GroupUserNameList'][$UserName] = $UserList[$UserName]['RealName'];
            }
        }
        else
        {
            foreach($GroupUserList as $UserName)
            {
                if($UserName != '')
                {
                    $LastRealName = $UserList[$UserName]['PreAppendName'];
                    $GroupList[$Key]['GroupUserList'][$UserName] = $LastRealName;
                    $GroupList[$Key]['GroupUserNameList'][$UserName] = $UserList[$UserName]['RealName'];
                }
            }
            foreach($GroupManagerList as $UserName)
            {
                if($UserName != '')
                {
                    $LastRealName = $UserList[$UserName]['PreAppendName'];
                    $GroupList[$Key]['GroupManagerList'][$UserName] = $LastRealName;
                    $GroupList[$Key]['GroupManagerNameList'][$UserName] = $UserList[$UserName]['RealName'];
                }
            }

        }
        natcasesort($GroupList[$Key]['GroupUserList']);
        $GroupList[$Key]['GroupUserSingleSelect'] = htmlSelect($GroupList[$Key]['GroupUserList'], 'GroupUserList','', '', 'class="FullSelect"');
        $GroupList[$Key]['GroupManagerSingleSelect'] = htmlSelect($GroupList[$Key]['GroupManagerList'], 'GroupManagerList','', '', 'class="FullSelect"');

        $GroupACLList = unserialize($GroupInfo['GroupACL']);
        if(!is_array($GroupACLList))
        {
            $GroupACLList = array();
        }
        $GroupList[$Key]['GroupProjectList'] = array();
        foreach($GroupACLList as $ProjectID => $ACLInfo)
        {
            $GroupList[$Key]['GroupProjectList'][$ProjectID] = $ProjectList[$ProjectID]['ProjectName'];
        }

        $GroupList[$Key]['GroupProjectSingleSelect'] = htmlSelect($GroupList[$Key]['GroupProjectList'], 'GroupProjectList', '', '', 'class="FullSelect"');
    }

    return $GroupList;
}
/**
 * Get group name list
 *
 * @author                   Rainy.Gao <zju_rain@163.com>
 * @param   string $Where    SQL condition
 * @param   string $OrderyBy SQL order by
 * @param   string $Limit    SQL limit m,n
 * @return  array  $GroupNameList
 */
function testGetGroupNameList($Where = '', $OrderBy = '', $Limit = '',$ContainNullUser = true)
{
		$GroupList = dbGetAllColumns('TestGroup', $Where, '', $OrderBy, $Limit, 'GroupID');
		$GroupNameList = array();
		foreach($GroupList as $Key => $GroupInfo)
		{
				$GroupNameList[$Key] = $GroupInfo['GroupName'];
		}
		
		if($ContainNullUser)
    {
        $GroupNameList = array(''=>'') + $GroupNameList;
    }
		
		return $GroupNameList;		
}
/*=======================================Group Functions End==============================*/

/*=======================================Bug Functions Start==============================*/
/**
 * Get BuildLisg
 *
 * @auhtor                  Yupeng Lee<leeyupeng@gmail.com>
 */
function testGetBugBuildList($ProjectID)
{
    $BuildList = dbGetList('BugInfo', 'OpenedBuild, COUNT(OpenedBuild) AS UsedTimes', "ProjectID = '{$ProjectID}'", 'OpenedBuild', 'OpenedBuild DESC, UsedTimes DESC', '10', 'OpenedBuild');
    $DayBuild = "1.0.".date("Ymd");
    $BuildList[$DayBuild] = array('OpenedBuild' => $DayBuild, 'UsedTimes' => '0');

    return $BuildList;
}

/*=== Local APIs for Bug Open Actions ======*/
function PostBugInfoPreHandler(&$PostBugInfo,$ProjectID,$ProjectInfo,$ModulePath)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostBugInfo as $Key => $Value)
    {
        if($_LANG['BugFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'BugTitle':
                	$PostBugInfo['BugTitle'] = sysDbSubStr(htmlspecialchars($PostBugInfo['BugTitle']),150);
                	break;
                	
								case 'BugContent':
                case 'ReproSteps':
 									//textfield format data convert
                	$PostBugInfo[$Key] = htmlspecialchars($PostBugInfo[$Key]);
                	break;
                
                case 'MailTo':
                	$MailToList = testGetMailToList(sysStripSlash($PostBugInfo['MailTo']), $ProjectID, true);
                	$PostBugInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
                
                case 'BugMachine':
                case 'BugKeyword':
									//input text format data convert
                	$PostBugInfo[$Key] = htmlspecialchars(trim($PostBugInfo[$Key]));
                	break;
                
                case 'DuplicateID':
                case 'LinkID':
                	$PostBugInfo[$Key] = dbGetValidValueList($PostBugInfo[$Key], 'BugInfo','BugID');
                	break;
                
                case 'CaseID':
                	$PostBugInfo[$Key] = dbGetValidValueList($PostBugInfo[$Key], 'CaseInfo','CaseID');
                	break;
            }
        }
    }
    
    if(isset($PostBugInfo['OpenedBuildInput']))
    {
    	$PostBugInfo['OpenedBuild'] = $PostBugInfo['OpenedBuildInput'] == "" ? $PostBugInfo['OpenedBuild'] : $PostBugInfo['OpenedBuildInput'];
    	$PostBugInfo['OpenedBuild'] = htmlspecialchars(trim($PostBugInfo['OpenedBuild']));
		}
		
		if(isset($PostBugInfo['ResolvedBuildInput']))
    {
			$PostBugInfo['ResolvedBuild'] = $PostBugInfo['ResolvedBuildInput'] == "" ? $PostBugInfo['ResolvedBuild'] : $PostBugInfo['ResolvedBuildInput'];
    	$PostBugInfo['ResolvedBuild'] = htmlspecialchars(trim($PostBugInfo['ResolvedBuild']));
    }
    
    //Set ProjectName and ModulePath
    if(isset($PostBugInfo['ProjectID']))
    {
    	$PostBugInfo['ProjectName'] = $ProjectInfo['ProjectName'];
    }

    if(isset($PostBugInfo['ModuleID']))
    {
    	$PostBugInfo['ModulePath'] = $ModulePath;
		}
		
		if(!empty($PostBugInfo['ReplyNote'])) 
		{   
    	$PostBugInfo['ReplyNote'] = htmlspecialchars($PostBugInfo['ReplyNote']);
    }
}

function OpenActionMsgInit($ActionObj)
{
	switch($ActionObj)
	{
		case 'Bug':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'BugID'=>'0');
			break;
		}
		case 'Change':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ChangeID'=>'0');
			break;
		}
		case 'Review':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ReviewID'=>'0');
			break;
		}
		case 'ReviewComment':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ReviewCommentID'=>'0');
			break;
		}
		case 'Plan':
		{
		  $ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'PlanID'=>'0', 'ActionID' => '0');
			break;
		}
		case 'Case':
		{
		  $ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'CaseID'=>'0', 'ActionID' => '0');
			break;
		}
	}
	return $ActionMsg;
}

function ValidateBugInfoFieldValue($PostBugInfo,$Key,&$ActionMsg)
{
		 global $_LANG;
		 switch($Key)
	   {
        		case 'ProjectID':
						case 'ProjectName':
						//case 'ModuleID':
						case 'ModulePath':
						case 'OpenedByDepartment':
						case 'AssignedToDepartment':
	  				case 'BugTitle':
	  				case 'BugType':
	  				case 'BugSeverity':
	  				case 'HowFound':
	  				case 'OpenedBuild':
	  				case 'BugContent':
	  					if($PostBugInfo[$Key] == '')
    					{
        				$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
    					}
	  					break;
	  				case 'ReproSteps':
	  					if($PostBugInfo[$Key] == '')
    					{
    						//For CodeError and ConfigError, Repro was mandatory
    						$BugTypeCheckList = array('Software','Config');
    						if(in_array($PostBugInfo['BugType'],$BugTypeCheckList))
    						{
        					$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
        				}
        			}
        			break;
        	case 'IsDuplicated':
          		if($PostBugInfo['IsDuplicated'] == 'Duplicate')
     					{
     						if(empty($PostBugInfo['DuplicateID']))
     						{
     							$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['DuplicateID'];	
     						}
     					}  			
        			break;
     }
}

function IsChangesClosed($IdStr)
{
    //Get the ChangeList by IdStr
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ChangeInfo') , 'ChangeStatus', "ChangeID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    Rainy_Debug($ResultList,__FUNCTION__,__LINE__,__FILE__);
    
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        if($InfoTmp['ChangeStatus'] != 'Closed')
        {
        		return false;
        }
    }
    return true;
}

function IsReviewsClosed($IdStr)
{
    //Get the ReviewList by IdStr
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ReviewInfo') , 'ReviewStatus', "ReviewID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    Rainy_Debug($ResultList,__FUNCTION__,__LINE__,__FILE__);
    
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        if($InfoTmp['ReviewStatus'] != 'Closed')
        {
        		return false;
        }
    }
    return true;
}

function IsReviewCommentsClosed($IdStr)
{
    //Get the ReviewCommentList by IdStr
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ReviewCommentInfo') , 'ReviewCommentStatus', "ReviewCommentID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    Rainy_Debug($ResultList,__FUNCTION__,__LINE__,__FILE__);
    
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        if($InfoTmp['ReviewCommentStatus'] != 'Closed')
        {
        		return false;
        }
    }
    return true;
}

function ValidateBugInfoResolvedFields($PostBugInfo,$RawBugInfo,&$ActionMsg)
{
				global $_LANG;
        if(empty($PostBugInfo['ResolvedBuild']))
        {
        		$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['ResolvedBuild'];
        }
        
        if(empty($PostBugInfo['Resolution']))
        {
        		$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['Resolution'];
        }
        
        //If User is Admin, Connect Change will not be checked
        if(!$_SESSION['TestIsAdmin'])
        {
        	if(IsChangesClosed($RawBugInfo['ChangeID']) == false)
					{
						$ActionMsg['FailedMsg'][] = $_LANG['ConnectedChangesNotClosed'];	
					}
				}
}

function ValidatePostOpenBugInfo($PostBugInfo,&$ActionMsg)
{		
		global $_LANG;
	  foreach($_LANG['BugFields'] as $Key => $Value)
	  {
	  		ValidateBugInfoFieldValue($PostBugInfo,$Key,$ActionMsg);
    }
}

function BuildSqlBugInsertArray($FieldList,$BugInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'BugID')
			{
					continue;
			}
					
			if(isset($BugInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $BugInfo[$Key];
			}
	}
}

function InsertBugInfo($PostBugInfo)
{
		global $_LANG;
		
		/* Build BugInfo */
		//Get Original PostBugInfo
		$BugInfo = $PostBugInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostBugInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
		
		//Set BugPriority    
    if($PostBugInfo['BugPriority'] == '')
    {
        $BugInfo['BugPriority'] = '';
    }
		    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $BugInfo['OpenedBy'] = $CurrentUser;	
   	$BugInfo['OpenedDate'] = $CurrentDate;
    $BugInfo['LastEditedBy'] = $CurrentUser;
   	$BugInfo['LastEditedDate'] = $CurrentDate;
    $BugInfo['ModifiedBy'] = $CurrentUser;
    
		//Set AssignedDate
    if($PostBugInfo['AssignedTo'] != '')
    {
        $AssignDate = $CurrentDate;
    }
    else
    {
        $AssignDate = '';
    }
 		$BugInfo['AssignedDate'] = $AssignDate;
    
    //Set BugStatus
    if(empty($PostBugInfo['BugStatus']))
    {
    	$BugInfo['BugStatus'] = 'Active';
    }
    
		//Create the ValueSqlString and KeySqlString
		$SqlInsertArray = array();
		BuildSqlBugInsertArray($_LANG['BugFields'],$BugInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$BugID = dbInsertFieldRow('BugInfo',$SqlInsertArray);
		
		return $BugID;
}

function UpdateOriginalResultInfo($ResultID,$BugID)
{
		if($ResultID > 0)
    {
    		$WhereStr = "ResultID={$ResultID}";
				$Key = 'BugID';
				$Value = "CONCAT(BugID,'{$BugID}',',')";
        dbUpdateRow('ResultInfo',$Key,$Value, $WhereStr);
    }
}

function ValidateCustomedFields($CustomedFields,$ActionObj,$ProjectInfo,&$ActionMsg)
{
        $xml = simplexml_load_string($ProjectInfo['FieldSet']);
        $fields = $xml->xpath('/fieldset/fields[@type="$ActionObj"]/field');
        $fields = sysFieldXmlToArr($fields);
        foreach ($fields as $field)
        {
            if($field['status'] != 'active')
            {
                continue;
            }
            $name = $field['name'];
            $CustomedFields["$name"] = htmlspecialchars($CustomedFields["$name"]);
            if($field['option'] != 'null')
            {
                if($CustomedFields["$name"] == '')
                {
                    $ActionMsg['FailedMsg'][] = $field['text'] . ' ' . $_LANG['NotNull'];
                }
            }
            if($field['type'] == 'text')
            {
                if(strlen($CustomedFields["$name"]) > 255)
                {
                    $ActionMsg['FailedMsg'][] = $field['text'] . ' ' . $_LANG['MaxLength'] . 255;
                }
            }
        }
}

function InsertCustomedFields($CustomedField,$ActionObj,$ActionObjID,$ProjectID)
{
    $TableName = testGetFieldTable($ActionObj, $ProjectID, true);

    $CustomedFields['FieldID'] = $ActionObjID;
    $valueSql = '"' . join('","', $CustomedFields) . '"';
    $keySql = join(',', array_keys($CustomedFields));
    dbInsertRow($TableName, $valueSql, $keySql);
}

function InsertAddAction($PostInfo,$ActionObj,$ActionObjID)
{
		$OpenedBy = $PostInfo['TestUserName'];
    $ActionID = testAddAction($ActionObj,$ActionObjID,$OpenedBy,'Opened','',$PostInfo['ReplyNote']);
		return $ActionID;
}

function GetEmailToListForOpenAction($ObjType,$PostInfo)
{
		//Build MailToStr	
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'Case':
		case 'Plan':
			if($PostInfo['AssignedTo'] != '')
			{
				$MailToStr = $PostInfo['AssignedTo'];
			}
			$MailToStr .= ','.$PostInfo['TestUserName'];
			break;
		case 'Review':
			if($PostInfo['Author'] != '')
			{
				$MailToStr = $PostInfo['Author'];
			}
			$MailToStr .= ','.$PostInfo['TestUserName'];
			$MailToStr .= ','.$PostInfo['Moderator'];
		  $MailToStr .= ','.$PostInfo['Recorder'];
		  $MailToStr .= ','.sysStripSlash($PostInfo['Inspectors']);
			break;
		case 'ReviewComment':
			$ReviewInfo = GetRawReviewInfo($PostInfo['ReviewID']);
			$MailToStr = $ReviewInfo['Author'];
			break;
		case 'User':
			$MailToStr = $PostInfo['UserName'];
			break;
		}
		Rainy_Debug($MailToStr,__FUNCTION__,__LINE__,__FILE__);
		
		//Get Email List	
		$ToList = testGetMailToList($MailToStr,$ProjectID, true);
		Rainy_Debug($ToList,__FUNCTION__,__LINE__,__FILE__);
		return $ToList['Email'];
}

function GetEmailCCListForOpenAction($ObjType,$PostInfo)
{
		//Build MailToStr	
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'Case':
		case 'Plan':
			$MailToStr = sysStripSlash($PostInfo['MailTo']);
			break;
		case 'Review':
		  $MailToStr = sysStripSlash($PostInfo['MailTo']);
			break;
		case 'ReviewComment':
			$ReviewInfo = GetRawReviewInfo($PostInfo['ReviewID']);
			$MailToStr = $PostInfo['ReviewCommentOwner'];
			$MailToStr .= ','.$PostInfo['TestUserName'];
			$MailToStr .= ','.$ReviewInfo['Moderator'];
		  $MailToStr .= ','.$ReviewInfo['Recorder'];
		  $MailToStr .= ','.sysStripSlash($ReviewInfo['Inspectors']);
		  $MailToStr .= ','.sysStripSlash($ReviewInfo['MailTo']);
			break;
		case 'User':
			$MailToStr = $PostInfo['TestUserName'];
			break;
		}
		Rainy_Debug($MailToStr,__FUNCTION__,__LINE__,__FILE__);
		
		//Get the MailToList from the MailTo Settings
		$CCList = testGetMailToList($MailToStr, $ProjectID, true);
		Rainy_Debug($CCList,__FUNCTION__,__LINE__,__FILE__);
		return $CCList['Email'];
}

function BuildMailContentForOpenAction($PostInfo,$FieldList)
{    
		$MailContent = '';
		
		if($PostInfo['ReplyNote'])
		{
			$MailContent .= $PostInfo['ReplyNote'] . "\n" . str_repeat("-", 20) . "\n" ;
		}
		
		foreach($FieldList as $Key => $Value)
		{
        if(($Key == 'ProjectID')||($Key == 'ModuleID'))
        {
        		continue;
        }
        
				if($PostInfo[$Key])
				{
        	$NewValue = FieldValueConvert($Key,$PostInfo[$Key]);
    	  	$NewValue = sysAddSlash($NewValue);
        	$KeyName = $Value;
          $MailContent .= "[b]{$KeyName}:[/b]  \"{$NewValue}\"\n";
        }
    }
    return $MailContent;
}

function SendOpenBugNotifyMail($PostBugInfo,$BugID,$ProjectID)
{
		global $_LANG;
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('Bug',$PostBugInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('Bug',$PostBugInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build BugMailTitle		
    $BugMailTitle = '['.$_LANG['TracSystem'].']'.' SR'.$BugID.' was raised: '.$PostBugInfo['BugTitle'];
    Rainy_Debug($BugMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Build MainMessage
 		$ActionUser = $PostBugInfo['TestUserName'];
 		$AssignedTo = $PostBugInfo['AssignedTo'];
 		$MailContent = BuildMailContentForOpenAction($PostBugInfo,$_LANG['BugFields']);
 		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($BugID,'Opened',$ActionUser,$AssignedTo,$MailContent,'Bug');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $BugMailTitle, $MainMessage);
}

/**
 * Open Bug
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostBugInfo
 * @return array  $ActionMsg
 */
function testOpenBug($PostBugInfo)
{	   
    //Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostBugInfo['ProjectID'];
    $ModuleID = $PostBugInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);

   	//Pre-Handler for PostBugInfo
		PostBugInfoPreHandler($PostBugInfo,$ProjectID,$ProjectInfo,$ModulePath);

		/***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Bug');	
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenBugInfo($PostBugInfo,$ActionMsg);
 
    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostBugInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$BugID = InsertBugInfo($PostBugInfo);
		$PostBugInfo['BugID'] = $BugID;
		
		//Update Original ResultInfo
    UpdateOriginalResultInfo($PostBugInfo['ResultID'],$BugID);

    //Insert Post Action
    $ActionID = InsertAddAction($PostBugInfo,'Bug',$BugID);

		//SendOpenBugNotifyMail
		SendOpenBugNotifyMail($PostBugInfo,$BugID,$ProjectID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['BugID'] = $BugID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

/*=== Local APIs for Bug Edit Actions ======*/
function EditActionMsgInit($ActionObj,$ActionObjID)
{
	switch($ActionObj)
	{
		case 'Bug':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'BugID'=>$ActionObjID, 'ActionID' => '0');
			break;
		}
		case 'Change':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ChangeID'=>$ActionObjID, 'ActionID' => '0');
			break;
		}
		case 'Review':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ReviewID'=>$ActionObjID, 'ActionID' => '0');
			break;
		}
		case 'ReviewComment':
		{
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ReviewCommentID'=>$ActionObjID, 'ActionID' => '0');
			break;
		}
		case 'Case':
			$ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'CaseID'=>$ActionObjID, 'ActionID' => '0');
			break;
	}
	return $ActionMsg;
}

function GetRawBugInfo($BugID)
{
		$Columns = '*';
  	$RawBugInfo = dbGetRow('BugInfo',$Columns,"BugID = '{$BugID}'");	
  	return $RawBugInfo;
}

function ValidatePostEditBugInfo($PostBugInfo,$RawBugInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostBugInfo as $Key => $Value)
    {
        if($_LANG['BugFields'][$Key])
       	{
						ValidateBugInfoFieldValue($PostBugInfo,$Key,$ActionMsg);
        }
    } 

    if($PostBugInfo['ActionType'] == 'Resolved')
    {
        if($RawBugInfo['BugStatus'] == 'Resolved')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyResolved'];
        }
        ValidateBugInfoResolvedFields($PostBugInfo,$RawBugInfo,$ActionMsg);
    }
    elseif($PostBugInfo['ActionType'] == 'Closed')
    {
        if($RawBugInfo['BugStatus'] == 'Closed')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyClosed'];
        }
        
        ValidateBugInfoResolvedFields($PostBugInfo,$RawBugInfo,$ActionMsg);
    }
    elseif($PostBugInfo['ActionType'] == 'Activated')
    {
        if($RawBugInfo['BugStatus'] == 'Active')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyActive'];
        }
    }
    
    $LastActionID = testGetLastActionID('Bug',$PostBugInfo['BugID']);
    if($PostBugInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['BugAlreadyChanged'];
    }
}

function GetDiffAssocStr($FieldList)
{
		$DiffAssocStr = '';
		foreach($FieldList as $Key => $Value)
		{
				if(empty($DiffAssocStr))
				{
					$DiffAssocStr = $Key;
				}
				else
				{
					$DiffAssocStr = $DiffAssocStr.','.$Key;
				}
		}
		return $DiffAssocStr;
}

function GetBugDiffInfo($PostBugInfo,$RawBugInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostBugInfo = sysStripSlash($PostBugInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['BugFields']);
		$BugDiffInfo = array();
    $BugDiffInfo += sysArrayDiffAssoc($TempPostBugInfo, $RawBugInfo, $DiffAssoc);
		
		//BugID should never be changed as BugDiffInfo
    if($BugDiffInfo['BugID'])
    {
    		unset($BugDiffInfo['BugID']);
    }
    
    return $BugDiffInfo;
}

function IsBugInfoChanged($BugDiffInfo,$PostBugInfo,$UploadFile)
{
		if(!empty($BugDiffInfo) || $PostBugInfo['ReplyNote'] != '' || $UploadFile || $PostBugInfo['ActionType'] == 'Closed' || $PostBugInfo['ActionType'] == 'Activated')
    {
			return true;
		}
		return false;
}

function BuildSqlSetArray($FieldList,$PostInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{	
			if(isset($PostInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $PostInfo[$Key];
			}
	}		
}

function EditBugInfo($BugID,$PostBugInfo,$RawBugInfo,$BugDiffInfo)
{
		global $_LANG;
		
		/* Build BugInfo */
		//Get Original BugDiffInfo
		$BugInfo = $BugDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostBugInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
		
		//Set the BugStatus ResolvedBy,ClosedBy...
    if($PostBugInfo['ActionType'] == 'Resolved')
    {
    	  $BugInfo['BugStatus'] =  'Resolved';
    		$BugInfo['ResolvedBy'] =  $CurrentUser;
    		$BugInfo['ResolvedDate'] =  $CurrentDate;
    }
    elseif($PostBugInfo['ActionType'] == 'Closed')
    {
        $BugInfo['BugStatus'] =  'Closed';
    		$BugInfo['ClosedBy'] = $CurrentUser;
    	 	$BugInfo['ClosedDate'] = $CurrentDate;
    }
    elseif($PostBugInfo['ActionType'] == 'Activated')
    {
        $BugInfo['BugStatus'] =  'Active';
        $BugInfo['ResolvedBy'] =  '';
        $BugInfo['ResolvedDate'] = '0000-00-00 00:00:00';
        $BugInfo['ClosedBy'] =  '';
        $BugInfo['ClosedDate'] = '0000-00-00 00:00:00';
    }
    
		//There is nothing to Update
    if(empty($BugInfo))
    {
    	 Rainy_Debug("No Field in BugInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $BugInfo['LastEditedBy'] = $CurrentUser;
    $BugInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$BugInfo['ModifiedBy'] = "{$RawBugInfo[ModifiedBy]},{$BugInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined BugFields
		$SqlSetArray = array();
		BuildSqlSetArray($_LANG['BugFields'],$BugInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the BugInfo
    dbUpdateFieldRow('BugInfo', $SqlSetArray, "BugID='{$BugID}'");
}

function GetRawCustomedFields($ActionObj,$ActionObjID,$ProjectID)
{
	$TableName = testGetFieldTable($ActionObj, $ProjectID, true);
	$RawFieldInfo = dbGetRow($TableName, null,"FieldID='{$ActionObjID}'");
	return $RawFieldInfo;
}

function GetCustomedFieldText($ActionObj,$ProjectInfo)
{
	  $fieldText = array();
		
		$xml = simplexml_load_string($ProjectInfo['FieldSet']);
    $fields = $xml->xpath('/fieldset/fields[@type="$ActionObj"]/field');
    $fields = sysFieldXmlToArr($fields);
    foreach ($fields as $field)
    {
    		if($field['status'] != 'active')
    		{
        		continue;
        }
        $name = $field['name'];
        $fieldText["$name"] = $field['text'];
    }
    return $fieldText;
}

function GetBugDiffInfoCustomedField(&$BugDiffInfo,$CustomedFields,$RawFieldInfo)
{
        foreach($CustomedFields as $key => $value)
        {
            if($key == 'FieldID')
            {
                continue;
            }
            if($value != sysAddSlash($RawFieldInfo[$key]))
            {
                $value = sysStripSlash($value);
                $BugDiffInfo[$key] = $value;
            }
        }
}

function UpdateCustomedFields(&$CustomedFields,$ActionObj,$ActionObjID)
{
		$TableName = testGetFieldTable($ActionObj, $ProjectID, true);
		$RawFieldInfo = dbGetRow($TableName, null,"FieldID='{$ActionObjID}'");
		
    if(!empty($RawFieldInfo))
    {
    	dbUpdateFieldRow($TableName, $CustomedFields, "FieldID='{$ActionObjID}'");
		}
    else
    {
    	$CustomedFields['FieldID'] = $ActionObjID;
      $valueSql = '"' . join('","', $CustomedFields) . '"';
     	$keySql = join(',', array_keys($CustomedFields));
      dbInsertRow($TableName, $valueSql, $keySql);
    }	
}

function InsertEditAction($PostInfo,$ActionObj,$ActionObjID,$ActionType)
{
   	//Get LastEditedBy
		$LastEditedBy = $PostInfo['TestUserName'];

		//Get ReplyNote
		$ReplyNote = $PostInfo['ReplyNote'];

		//Get ActionType
   	if(empty($PostInfo['ActionType']))
   	{
   		$ActionType = 'Edited';
   	}
   	else
   	{
   		$ActionType = $PostInfo['ActionType'];	
   	}
   	
   	//Update the Duplicated BugID's ActionInfo
   	if(($ActionType == 'Resolved') && ($ActionObj == 'Bug'))
   	{
   			if($PostInfo['Resolution'] == 'Duplicate')
   			{
   					$ChangeNote = "Bug #[bug]{$PostInfo[BugID]}[/bug] is resolved as duplicate to this bug.";
   					$DuplicateList = explode(',', $PostInfo['DuplicateID']);
            foreach($DuplicateList as $DupID)
            {
                $ActionID = testAddAction('Bug', $DupID, $LastEditedBy, 'Edited', '', $ChangeNote);
            }	
        }
   	}
   	
 		//Insert Action
    $ActionID =  testAddAction($ActionObj,$ActionObjID,$LastEditedBy,$ActionType,'',$ReplyNote);
		return $ActionID;
}

function InsertEditHistoryInfo($ActionID,$RawInfo,$DiffInfo)
{
    foreach($DiffInfo as $Key => $Value)
    {
        $OldValue = $RawInfo[$Key];
        $NewValue = $DiffInfo[$Key];
        testAddHistory($ActionID, $Key, $OldValue, $NewValue);
    }
}

function GetEmailToListForEditAction($ObjType,$PostInfo,$RawInfo,$DiffInfo)
{
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'Case':
		case 'Plan':
			//Build MailToStr
			$MailToStr = $PostInfo['TestUserName'];
			if($DiffInfo['AssignedTo'] != '')
			{
					$MailToStr = $MailToStr.','.$DiffInfo['AssignedTo'];
			}
			if($RawBugInfo['AssignedTo'] != '')
			{
					$MailToStr = $MailToStr.','.$RawBugInfo['AssignedTo'];
			}
			break;
		case 'Review':
			//Build MailToStr
			$MailToStr = $PostInfo['TestUserName'];
			$MailToStr .= ','.GetEditReviewFieldValue('Author',$PostInfo,$RawInfo,$DiffInfo);
			$MailToStr .= ','.GetEditReviewFieldValue('Moderator',$PostInfo,$RawInfo,$DiffInfo);
			$MailToStr .= ','.GetEditReviewFieldValue('Recorder',$PostInfo,$RawInfo,$DiffInfo);
			$MailToStr .= ','.GetEditReviewFieldValue('Inspectors',$PostInfo,$RawInfo,$DiffInfo);
			break;
		case 'ReviewComment':
			$ReviewInfo = GetRawReviewInfo($RawInfo['ReviewID']);
			$MailToStr = $ReviewInfo['Author'];
			break;
		case 'User':
			//Build MailToStr
			if($DiffInfo['UserName'] != '')
			{
					$MailToStr = $DiffInfo['UserName'];
			}
			else
			{
					$MailToStr = $RawInfo['UserName'];
			}
			break;
		}
		Rainy_Debug($MailToStr,__FUNCTION__,__LINE__,__FILE__);
		
		//Get Email List
		$ToList = testGetMailToList($MailToStr);
		Rainy_Debug($ToList,__FUNCTION__,__LINE__,__FILE__);
		return $ToList['Email'];
}

function GetEmailCCListForEditAction($ObjType,$PostInfo,$RawInfo,$DiffInfo)
{
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'Case':
		case 'Plan':
			//OpenBug Email should be copied to MailTo,OpenedByDepartment,AssignedToDepartment
				if($DiffInfo['MailTo'] != '')
				{
						$MailToStr = sysStripSlash($DiffInfo['MailTo']);
				}
				if($RawInfo['MailTo'] != '')
				{
						$MailToStr = $MailToStr.','.sysStripSlash($RawInfo['MailTo']);
				}
				break;
		case 'Review':
				if($DiffInfo['Moderator'] != '')
				{
						$MailToStr .= ','.$RawInfo['Moderator'];
				}
				if($DiffInfo['Recorder'] != '')
				{
						$MailToStr .= ','.$RawInfo['Recorder'];
				}				
				if($DiffInfo['Inspectors'] != '')
				{
						$MailToStr .= ','.sysStripSlash($RawInfo['Inspectors']);
				}
				if($DiffInfo['MailTo'] != '')
				{
						$MailToStr .= ','.sysStripSlash($DiffInfo['MailTo']);
				}
				if($RawInfo['MailTo'] != '')
				{
						$MailToStr .= ','.sysStripSlash($RawInfo['MailTo']);
				}						
				break;
		case 'ReviewComment':
			$ReviewInfo = GetRawReviewInfo($RawInfo['ReviewID']);
			$MailToStr = $RawInfo['ReviewCommentOwner'];
			$MailToStr .= ','.$PostInfo['TestUserName'];
			$MailToStr .= ','.$ReviewInfo['Moderator'];
		  $MailToStr .= ','.$ReviewInfo['Recorder'];
		  $MailToStr .= ','.sysStripSlash($ReviewInfo['Inspectors']);
		  $MailToStr .= ','.sysStripSlash($ReviewInfo['MailTo']);
			break;
		case 'User':
			//Build MailToStr
			$MailToStr = $PostInfo['TestUserName'];
			break;
		}
		Rainy_Debug($MailToStr,__FUNCTION__,__LINE__,__FILE__);
		
		//Get the MailToList from the MailTo Settings
		$CCList = testGetMailToList($MailToStr);
		Rainy_Debug($CCList,__FUNCTION__,__LINE__,__FILE__);
		return $CCList['Email'];
}

function FieldValueConvert($FieldName,$FieldValue)
{
		global $_LANG;
		
		switch($FieldName)
		{
		//Bug Related
		case 'BugType':
			$RetValue = $_LANG['BugTypes'][$FieldValue];
			break;
		case 'BugStatus':
			$RetValue = $_LANG['BugStatus'][$FieldValue];
			break;
		case 'BugSubStatus':
			$RetValue = $_LANG['BugSubStatus'][$FieldValue];
			break;
		case 'Resolution':
			$RetValue = $_LANG['BugResolutions'][$FieldValue];
			break;
		case 'HowFound':
			$RetValue = $_LANG['BugHowFound'][$FieldValue];
			break;
		case 'BugSeverity':
			$RetValue = $_LANG['BugSeveritys'][$FieldValue];
			break;		
		case 'BugPriority':
			$RetValue = $_LANG['BugPriorities'][$FieldValue];
			break;
		//Change Related
		case 'ChangeType':
			$RetValue = $_LANG['ChangeTypes'][$FieldValue];
			break;
		case 'ChangeStatus':
			$RetValue = $_LANG['ChangeStatus'][$FieldValue];
			break;
		//Review Related
		case 'ReviewType':
			$RetValue = $_LANG['ReviewTypes'][$FieldValue];
			break;		
		case 'ReviewStatus':
			$RetValue = $_LANG['ReviewStatus'][$FieldValue];
			break;			
		case 'StartTime':
		case 'EndTime':
			$RetValue = $_LANG['TimeList'][$FieldValue];
			break;
		case 'ReviewConclusion':
			$RetValue = $_LANG['ReviewConclusions'][$FieldValue];
			break;
		default:
			$RetValue = $FieldValue;
			break;
		}
		Rainy_Debug($RetValue,__FUNCTION__,__LINE__,__FILE__);
		return $RetValue;
}

function BuildMailContentForEditAction($PostInfo,$RawInfo,$DiffInfo,$FieldList)
{
		$MailContent = '';
		
		if($PostInfo['ReplyNote'])
		{
			$MailContent .= $PostInfo['ReplyNote'] . "\n" . str_repeat("-", 20) . "\n" ;
		}
		
		foreach($FieldList as $Key => $Value)
		{
        if(($Key == 'ProjectID')||($Key == 'ModuleID'))
        {
        		continue;
        }
        
				if($DiffInfo[$Key])
				{
        	$OldValue = FieldValueConvert($Key,$RawInfo[$Key]);
	      	$NewValue = FieldValueConvert($Key,$DiffInfo[$Key]);
	      	$OldValue = sysAddSlash($OldValue);
    	  	$NewValue = sysAddSlash($NewValue);
        	$KeyName = $Value;
          $MailContent .= "Changed [b]{$KeyName}[/b] from [b]\"{$OldValue}\"[/b] to[b]\"{$NewValue}\"[/b]\n";
        }
    }
    return $MailContent;
}

function SendEditBugNotifyMail($BugID,$PostBugInfo,$RawBugInfo,$BugDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('Bug',$PostBugInfo,$RawBugInfo,$BugDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('Bug',$PostBugInfo,$RawBugInfo,$BugDiffInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostBugInfo['ActionType'];
    Rainy_Debug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set BugMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] SR'.$BugID.' was '.$ActionType.': ';
    $BugMailTitle = $MailPrefix.$PostBugInfo['BugTitle'];
    Rainy_Debug($BugMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostBugInfo['TestUserName'];
 		$AssignedTo = $PostBugInfo['AssignedTo'];
    $MailContent = BuildMailContentForEditAction($PostBugInfo,$RawBugInfo,$BugDiffInfo,$_LANG['BugFields']);
    $MainMessage = testCreateMailMessage($BugID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'Bug');
    Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $BugMailTitle, $MainMessage);
}

/**
 * Edit Bug
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostBugInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditBug($PostBugInfo, $UploadFile = false)
{
    global $_LANG;
    
    Rainy_Debug($PostBugInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Get BugID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $BugID = $PostBugInfo['BugID'];
		
    //Get RawBugInfo
    $RawBugInfo = GetRawBugInfo($BugID);
		
		//ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostBugInfo['ProjectID'];
    $ModuleID = $PostBugInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostBugInfo
		PostBugInfoPreHandler($PostBugInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_Debug($PostBugInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Bug',$BugID);
		
		//Validate PostBugInfo
		ValidatePostEditBugInfo($PostBugInfo,$RawBugInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostBugInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }
	  
		//GetBugDiffInfo
		$BugDiffInfo = GetBugDiffInfo($PostBugInfo,$RawBugInfo,$ProjectInfo,$ModulePath);
		Rainy_Debug($BugDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update BugInfo
		EditBugInfo($BugID,$PostBugInfo,$RawBugInfo,$BugDiffInfo);

		//Check if BugInfo was changed
    if(IsBugInfoChanged($BugDiffInfo,$PostBugInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    $ActionID = InsertEditAction($PostBugInfo,'Bug',$BugID);

    //Add the Histroy Info to the EditAction
    InsertEditHistoryInfo($ActionID,$RawBugInfo,$BugDiffInfo);
    
		//Send Notify Email
		Rainy_Debug($PostBugInfo['SendNotifyEmail'],__FUNCTION__,__LINE__,__FILE__);
		if($PostBugInfo['SendNotifyEmail'] == 'SendNotifyEmail')
		{
			SendEditBugNotifyMail($BugID,$PostBugInfo,$RawBugInfo,$BugDiffInfo,$UploadFile);
		}
		
		$ActionMsg['ActionID'] = $ActionID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for Change Open Actions ======*/
function ConvertBugTypeToChangeType($BugType)
{
		global $_LANG;

		//Rainy_Debug($BugType,__FUNCTION__,__LINE__,__FILE__);
		
		$ChangeType = '';
		foreach($_LANG['ChangeTypes'] as $Key => $Value)
		{
				if($BugType == $Key)
				{
						$ChangeType = $BugType;
						break;
				}
		}
		
		//Rainy_Debug($ChangeType,__FUNCTION__,__LINE__,__FILE__);
		
		return $ChangeType;
}

function PostChangeInfoPreHandler(&$PostChangeInfo,$ProjectID,$ProjectInfo,$ModulePath)
{
		global $_LANG;
		
	
		/* Do String Convert */    
    foreach($PostChangeInfo as $Key => $Value)
    {
        if($_LANG['ChangeFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'ChangeTitle':
                	$PostChangeInfo['ChangeTitle'] = sysDbSubStr(htmlspecialchars($PostChangeInfo['ChangeTitle']),150);
                	break;
                	
                case 'RootCause':
								case 'Resolution':
 									//textfield format data convert
                	$PostChangeInfo[$Key] = htmlspecialchars($PostChangeInfo[$Key]);
                	break;
                
                case 'MailTo':
                	$MailToList = testGetMailToList(sysStripSlash($PostChangeInfo['MailTo']), $ProjectID, true);
                	$PostChangeInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
            }
        }
    }
    
    if(isset($PostChangeInfo['OpenedBuildInput']))
    {
    	$PostChangeInfo['OpenedBuild'] = $PostChangeInfo['OpenedBuildInput'] == "" ? $PostChangeInfo['OpenedBuild'] : $PostChangeInfo['OpenedBuildInput'];
    	$PostChangeInfo['OpenedBuild'] = htmlspecialchars(trim($PostChangeInfo['OpenedBuild']));
		}
		
		if(isset($PostChangeInfo['ResolvedBuildInput']))
    {
			$PostChangeInfo['ResolvedBuild'] = $PostChangeInfo['ResolvedBuildInput'] == "" ? $PostChangeInfo['ResolvedBuild'] : $PostChangeInfo['ResolvedBuildInput'];
    	$PostChangeInfo['ResolvedBuild'] = htmlspecialchars(trim($PostChangeInfo['ResolvedBuild']));
    }
    //Set ProjectName and ModulePath
    if(isset($PostChangeInfo['ProjectID']))
    {
    	$PostChangeInfo['ProjectName'] = $ProjectInfo['ProjectName'];
    }
    if(isset($PostChangeInfo['ModuleID']))
    {
    	$PostChangeInfo['ModulePath'] = $ModulePath;
		}
		if($PostChangeInfo['BugID'])
    {
    		$RawBugInfo = GetRawBugInfo($PostChangeInfo['BugID']);
    		$PostChangeInfo['ProjectID'] 	 = 	$RawBugInfo['ProjectID'];	
    		$PostChangeInfo['ProjectName'] = 	$RawBugInfo['ProjectName'];	
    		$PostChangeInfo['ModuleID']    = 	$RawBugInfo['ModuleID'];
    		$PostChangeInfo['ModulePath']  = 	$RawBugInfo['ModulePath'];
    }

		if(!empty($PostChangeInfo['ReplyNote'])) 
		{   
    	$PostChangeInfo['ReplyNote'] = htmlspecialchars($PostChangeInfo['ReplyNote']);
    }
}

function ValidateChangeInfoFieldValue($PostChangeInfo,$Field,&$ActionMsg)
{
		global $_LANG;
		switch($Field)
  	{
  	case 'ProjectID':
		case 'ProjectName':
		//case 'ModuleID':
		case 'ModulePath':
		//case 'OpenedByDepartment':
		//case 'AssignedToDepartment':
		case 'ChangeTitle':
		case 'ChangeType':
		//case 'ChangeStatus':
		case 'OpenedBuild':
	  		if($PostChangeInfo[$Field] == '')
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Field];
      	}
        break;
  	}			
}

function ValidateChangeInfoResolvedFields($PostChangeInfo,$RawChangeInfo,&$ActionMsg)
{
		global $_LANG;
		//ResolvedBuild Check
    if(empty($PostChangeInfo['ResolvedBuild']))
    {
    	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['ResolvedBuild'];
    }
    		
    //RootCause Check    		
    if(empty($PostChangeInfo['RootCause']))
    {
    	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['RootCause'];
    }
    		
    //Resolution Check
    if(empty($PostChangeInfo['Resolution']))
    {
    	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['Resolution'];
   	}	
    
    //If User is Admin, Connect Review will not be checked
    if(!$_SESSION['TestIsAdmin'])
    {
    	if(IsReviewsClosed($RawChangeInfo['ReviewID']) == false)
			{
					$ActionMsg['FailedMsg'][] = $_LANG['ConnectedReviewsNotClosed'];	
			}
		}
}

function ValidatePostOpenChangeInfo($PostChangeInfo,&$ActionMsg)
{		
		global $_LANG;
	  
	  foreach($_LANG['ChangeFields'] as $Key => $Value)
	  {
	  	ValidateChangeInfoFieldValue($PostChangeInfo,$Key,$ActionMsg);
    }
}

function ValidatePostEditChangeInfo($PostChangeInfo,$RawChangeInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostChangeInfo as $Key => $Value)
    {
        if($_LANG['ChangeFields'][$Key])
        {
        		ValidateChangeInfoFieldValue($PostChangeInfo,$Key,$ActionMsg);
        }
    }

    if($PostChangeInfo['ActionType'] == 'Resolved')
    {
        //Check the previos status
        if($RawChangeInfo['ChangeStatus'] == 'Resolved')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyResolved'];
        }
        
        ValidateChangeInfoResolvedFields($PostChangeInfo,$RawChangeInfo,$ActionMsg);        
    }
    elseif($PostChangeInfo['ActionType'] == 'Closed')
    {
        if($RawChangeInfo['ChangeStatus'] == 'Closed')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyClosed'];
        }         
        ValidateChangeInfoResolvedFields($PostChangeInfo,$RawChangeInfo,$ActionMsg); 
    }
    elseif($PostChangeInfo['ActionType'] == 'Activated')
    {
        if($RawChangeInfo['ChangeStatus'] == 'Active')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyActive'];
        }
    }
    
    $LastActionID = testGetLastActionID('Change',$PostChangeInfo['ChangeID']);
    if($PostChangeInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['ChangeAlreadyChanged'];
    }
}

function BuildSqlChangeInsertArray($FieldList,$ChangeInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'ChangeID')
			{
					continue;
			}
					
			if(isset($ChangeInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $ChangeInfo[$Key];
			}
	}
}

function InsertChangeInfo($PostChangeInfo)
{   
		global $_LANG;
		
		/* Build ChangeInfo */
		//Get Original PostChangeInfo
		$ChangeInfo = $PostChangeInfo;
		
		//Get CurretnUser and CurrentDate
    $CurrentUser = $PostChangeInfo['TestUserName'];
    $CurrentDate = date('Y-m-d H:i:s');
    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $ChangeInfo['OpenedBy'] = $CurrentUser;	
   	$ChangeInfo['OpenedDate'] = $CurrentDate;
    $ChangeInfo['LastEditedBy'] = $CurrentUser;
   	$ChangeInfo['LastEditedDate'] = $CurrentDate;
    $ChangeInfo['ModifiedBy'] = $CurrentUser;
    
    //Set AssignedDate
    if($PostChangeInfo['AssignedTo'] != '')
    {
        $AssignDate = $CurrentDate;
    }
    else
    {
        $AssignDate = '';
    }
    $ChangeInfo['AssignedDate'] = $AssignDate;
    
    //Set BugStatus
    if(empty($PostChangeInfo['ChangeStatus']))
    {
    	$ChangeInfo['ChangeStatus'] = 'Active';
    }
 
 		//Create the SqlInsertArray
		$SqlInsertArray = array();
		BuildSqlChangeInsertArray($_LANG['ChangeFields'],$ChangeInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$ChangeID = dbInsertFieldRow('ChangeInfo',$SqlInsertArray);
		
		return $ChangeID;
}

function UpdateOriginalBugInfo($BugID,$ChangeID)
{
		Rainy_Debug($BugID,__FUNCTION__,__LINE__,__FILE__,0);
		if($BugID > 0)
    {
    		$WhereStr = "BugID={$BugID}";
				$Key = 'ChangeID';
				$Value = "CONCAT(ChangeID,'{$ChangeID}',',')";
				Rainy_Debug($WhereStr,__FUNCTION__,__LINE__,__FILE__,0);
        Rainy_Debug($Key,__FUNCTION__,__LINE__,__FILE__,0);
        Rainy_Debug($Value,__FUNCTION__,__LINE__,__FILE__,0);
        dbUpdateRow('BugInfo',$Key,$Value, $WhereStr);
    }
}

function SendOpenChangeNotifyMail($PostChangeInfo,$ChangeID,$ProjectID)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('Change',$PostChangeInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('Change',$PostChangeInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build ChangeMailTitle		
    $ChangeMailTitle = '['.$_LANG['TracSystem'].']'.' CR'.$ChangeID.' was raised: '.$PostChangeInfo['ChangeTitle'];
    
    //Build MainMessage
 		$ActionUser = $PostChangeInfo['TestUserName'];
 		$AssignedTo = $PostChangeInfo['AssignedTo'];
 		$MailContent = BuildMailContentForOpenAction($PostChangeInfo,$_LANG['ChangeFields']);
 		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($ChangeID,'Opened',$ActionUser,$AssignedTo,$MailContent,'Change');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ChangeMailTitle, $MainMessage);
}

/**
 * Open Change
 *
 * @author                     Rainy Gao<zju_rain@163.com>
 * @param  array  $PostChangeInfo
 * @return array  $ActionMsg
 */
function testOpenChange($PostChangeInfo)
{
		//Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostChangeInfo['ProjectID'];
    $ModuleID = $PostChangeInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
    //Pre-Handler for PostChangeInfo
		PostChangeInfoPreHandler($PostChangeInfo,$ProjectID,$ProjectInfo,$ModulePath);

    /***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Change');		
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenChangeInfo($PostChangeInfo,$ActionMsg);

    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostChangeInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$ChangeID = InsertChangeInfo($PostChangeInfo);
		
		//Update Original BugInfo
		Rainy_Debug($PostChangeInfo['BugID'],__FUNCTION__,__LINE__,__FILE__,0);
		UpdateOriginalBugInfo($PostChangeInfo['BugID'],$ChangeID);

    //Insert Post Action
    $ActionID = InsertAddAction($PostChangeInfo,'Change',$ChangeID);

		//SendOpenChangeNotifyMail
		SendOpenChangeNotifyMail($PostChangeInfo,$ChangeID,$ProjectID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['ChangeID'] = $ChangeID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

/*=== Local APIs for Change Edit Actions ======*/
function GetRawChangeInfo($ChangeID)
{
		$Columns = '*';
  	$RawChangeInfo = dbGetRow('ChangeInfo',$Columns,"ChangeID = '{$ChangeID}'");	
  	return $RawChangeInfo;
}

function GetChangeDiffInfo($PostChangeInfo,$RawChangeInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostChangeInfo = sysStripSlash($PostChangeInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['ChangeFields']);
		$ChangeDiffInfo = array();
    $ChangeDiffInfo += sysArrayDiffAssoc($TempPostChangeInfo, $RawChangeInfo, $DiffAssoc);
		
		//ChangeID should never be changed as ChangeDiffInfo
    if($ChangeDiffInfo['ChangeID'])
    {
    		unset($ChangeDiffInfo['ChangeID']);
    }
    
    return $ChangeDiffInfo;
}

function IsChangeInfoChanged($ChangeDiffInfo,$PostChangeInfo,$UploadFile)
{
		if(!empty($ChangeDiffInfo) || $PostChangeInfo['ReplyNote'] != '' || $UploadFile || $PostChangeInfo['ActionType'] == 'Closed' || $PostChangeInfo['ActionType'] == 'Activated')
    {
			return true;
		}
		return false;
}

function BuildSqlChangeSetArray($FieldList,$ChangeInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//ChangeID should not be Changed
			if($Key == 'ChangeID')
			{
					continue;
			}
			
			if(isset($ChangeInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $ChangeInfo[$Key];
			}
	}		
}

function EditChangeInfo($ChangeID,$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo)
{
		global $_LANG;
		
		/* Build ChangeInfo */
		//Get Original ChangeDiffInfo
		$ChangeInfo = $ChangeDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostChangeInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
		
		//Set the ChangeStatus ResolvedBy,ClosedBy...
    if($PostChangeInfo['ActionType'] == 'Resolved')
    {
    	  $ChangeInfo['ChangeStatus'] =  'Resolved';
    		$ChangeInfo['ResolvedBy'] =  $CurrentUser;
    		$ChangeInfo['ResolvedDate'] =  $CurrentDate;
    }
    elseif($PostChangeInfo['ActionType'] == 'Closed')
    {
        $ChangeInfo['ChangeStatus'] =  'Closed';
    		$ChangeInfo['ClosedBy'] = $CurrentUser;
    	 	$ChangeInfo['ClosedDate'] = $CurrentDate;
    }
    elseif($PostChangeInfo['ActionType'] == 'Activated')
    {
        $ChangeInfo['ChangeStatus'] =  'Active';
        $ChangeInfo['ResolvedBy'] =  '';
        $ChangeInfo['ResolvedDate'] = '0000-00-00 00:00:00';
        $ChangeInfo['ClosedBy'] =  '';
        $ChangeInfo['ClosedDate'] = '0000-00-00 00:00:00';
    }
    
		//There is nothing to Update
    if(empty($ChangeInfo))
    {
    	 Rainy_Debug("No Fields in ChangeInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $ChangeInfo['LastEditedBy'] = $CurrentUser;
    $ChangeInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$ChangeInfo['ModifiedBy'] = "{$RawChangeInfo[ModifiedBy]},{$ChangeInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined ChangeFields
		$SqlSetArray = array();
		BuildSqlChangeSetArray($_LANG['ChangeFields'],$ChangeInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the ChangeInfo
    dbUpdateFieldRow('ChangeInfo', $SqlSetArray, "ChangeID='{$ChangeID}'");
}

function SendEditChangeNotifyMail($ChangeID,$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('Change',$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('Change',$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostChangeInfo['ActionType'];
    Rainy_Debug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set ChangeMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] CR'.$ChangeID.' was '.$ActionType.': ';
    $ChangeMailTitle = $MailPrefix.$PostChangeInfo['ChangeTitle'];
    Rainy_Debug($ChangeMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostChangeInfo['TestUserName'];
 		$AssignedTo = $PostChangeInfo['AssignedTo'];
    $MailContent = BuildMailContentForEditAction($PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo,$_LANG['ChangeFields']);
    Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($ChangeID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'Change', $ActionDesc);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ChangeMailTitle, $MainMessage);
}

/**
 * Edit Change
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostChangeInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditChange($PostChangeInfo, $UploadFile = false)
{
    global $_LANG;
    
    //Get ChangeID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $ChangeID = $PostChangeInfo['ChangeID'];
		$ProjectID = $PostChangeInfo['ProjectID'];
    $ModuleID = $PostChangeInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostChangeInfo
		PostChangeInfoPreHandler($PostChangeInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_Debug($PostChangeInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Change',$ChangeID);
		
		//Get RawChangeInfo
    $RawChangeInfo = GetRawChangeInfo($ChangeID);
		//Rainy_Debug($PostChangeInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Validate PostChangeInfo
		ValidatePostEditChangeInfo($PostChangeInfo,$RawChangeInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostChangeInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }
	  
		//GetChangeDiffInfo
		$ChangeDiffInfo = GetChangeDiffInfo($PostChangeInfo,$RawChangeInfo,$ProjectInfo,$ModulePath);
		//Rainy_Debug($ChangeDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update ChangeInfo
		EditChangeInfo($ChangeID,$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo);

		//Check if ChangeInfo was changed
    if(IsChangeInfoChanged($ChangeDiffInfo,$PostChangeInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    $ActionID = InsertEditAction($PostChangeInfo,'Change',$ChangeID);

    //Add the Histroy Info to the EditAction
    InsertEditHistoryInfo($ActionID,$RawChangeInfo,$ChangeDiffInfo);
    
		//Send Notify Email
		Rainy_Debug($PostChangeInfo['SendNotifyEmail'],__FUNCTION__,__LINE__,__FILE__);
		if($PostChangeInfo['SendNotifyEmail'] == 'SendNotifyEmail')
		{
			SendEditChangeNotifyMail($ChangeID,$PostChangeInfo,$RawChangeInfo,$ChangeDiffInfo,$UploadFile);
		}
		
		$ActionMsg['ActionID'] = $ActionID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for Review Open Actions ======*/
function PostReviewInfoPreHandler(&$PostReviewInfo,$ProjectID,$ProjectInfo,$ModulePath)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostReviewInfo as $Key => $Value)
    {
        if($_LANG['ReviewFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'ReviewTitle':
                	$PostReviewInfo['ReviewTitle'] = sysDbSubStr(htmlspecialchars($PostReviewInfo['ReviewTitle']),150);
                	break;
                	
                case 'MailTo':
                case 'Inspectors':
                	$MailToList = testGetMailToList(sysStripSlash($PostReviewInfo[$Key]), $ProjectID, true);
                	$PostReviewInfo[$Key] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
            }
        }
    }
    
    //Set ProjectName and ModulePath
    if(isset($PostReviewInfo['ProjectID']))
    {
    	$PostReviewInfo['ProjectName'] = $ProjectInfo['ProjectName'];
    }
    if(isset($PostReviewInfo['ModuleID']))
    {
    	$PostReviewInfo['ModulePath'] = $ModulePath;
		}
    if($PostReviewInfo['ChangeID'])
    {
    		$RawChangeInfo = GetRawChangeInfo($PostReviewInfo['ChangeID']);
    		$PostReviewInfo['ProjectID']   = 	$RawChangeInfo['ProjectID'];	
    		$PostReviewInfo['ProjectName'] = 	$RawChangeInfo['ProjectName'];
    		$PostReviewInfo['ModuleID']    = 	$RawChangeInfo['ModuleID'];	
    		$PostReviewInfo['ModulePath']  = 	$RawChangeInfo['ModulePath'];
    }
		
		//If Author was not set, Set it to CurrentUser
		if(empty($PostReviewInfo['Author'])) 
		{
				$PostReviewInfo['Author'] = $PostReviewInfo['TestUserName'];
		}
		
		if(!empty($PostReviewInfo['ReplyNote'])) 
		{   
    	$PostReviewInfo['ReplyNote'] = htmlspecialchars($PostReviewInfo['ReplyNote']);
    }
}

function ValidateReviewInfoFieldValue($PostReviewInfo,$Key,&$ActionMsg)
{
		global $_LANG;
		switch($Key)
  	{
  	case 'ProjectID':
		case 'ProjectName':
		//case 'ModuleID':
		case 'ModulePath':
		case 'ReviewTitle':
		case 'ReviewType':
		//case 'ReviewStatus':
		case 'MeetingDate':
		//case 'StartTime':
		//case 'EndTime':
		case 'MeetingLocation':
		case 'Author':
		case 'Inspectors':
				if(empty($PostReviewInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
        break;
		case 'ReviewContent':
				if(empty($PostReviewInfo[$Key]) || $PostReviewInfo[$Key]== $_LANG['ReviewContentReminder'])
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}  			
				break;        
    case 'Moderator':
		  	if(empty($PostReviewInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
		  	if($PostReviewInfo['Moderator'] == $PostReviewInfo['Author'])
  			{
  					$ActionMsg['FailedMsg'][] = $_LANG['ModeratorSameWithAuthor'];
  			}
  			break;			
		case 'Recorder':
		  	if(empty($PostReviewInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
		  	if($PostReviewInfo['Recorder'] == $PostReviewInfo['Author'])
  			{
  					$ActionMsg['FailedMsg'][] = $_LANG['RecorderSameWithAuthor'];
  			}
  			break;
  	case 'EndTime':
  			if($PostReviewInfo['EndTime'] < $PostReviewInfo['StartTime'])
  			{
  					$ActionMsg['FailedMsg'][] = $_LANG['StartTimeLaterThanEndTime'];
  			}
  			break;
  	}	
}

function ReviewConclusionConfirm($PostReviewInfo,$RawReviewInfo,&$ActionMsg)
{
		global $_LANG;
		
		if(empty($PostReviewInfo['ReviewConclusion']))
		{
				$ReviewConclusion = $RawReviewInfo['ReviewConclusion'];
		}
		else
		{
				$ReviewConclusion = $PostReviewInfo['ReviewConclusion'];
		}
		
		switch($ReviewConclusion)
		{
		case 'Passed':
				//Review Passed no need any fixing
    		break;
    case 'PassedNeedFix':
				//Review Passed but need change
    		if(empty($RawReviewInfo['ReviewCommentID']))
    		{
    				$ActionMsg['FailedMsg'][] = $_LANG['ConnectedReviewCommentsNotSet'];
    		}
    		break;
    case 'Failed':
    		//Review Failed
				$ActionMsg['FailedMsg'][] = $_LANG['NotPassedReviewCanNotBeClosed'];
				break;
		case 'ToBeContinue':
				//Review ToBeContinue
				$ActionMsg['FailedMsg'][] = $_LANG['NotCompletedReviewCanNotBeClosed'];
				break;		
		}
}

function ValidateReviewInfoResolvedFields($PostReviewInfo,$RawReviewInfo,&$ActionMsg)
{
		global $_LANG;
		//ResolvedBuild Check
    if(empty($PostReviewInfo['ReviewConclusion']))
    {
    	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['ReviewConclusion'];
    }
    
    //If User is Admin, Connect ReviewComment will not be checked
    if(!$_SESSION['TestIsAdmin'])
    {
    	ReviewConclusionConfirm($PostReviewInfo,$RawReviewInfo,$ActionMsg);			
    	if(IsReviewCommentsClosed($RawReviewInfo['ReviewCommentID']) == false)
			{
					$ActionMsg['FailedMsg'][] = $_LANG['ConnectedReviewCommentsNotClosed'];	
			}
		}
}

function ValidatePostOpenReviewInfo($PostReviewInfo,&$ActionMsg)
{		
		global $_LANG;
	  
	  foreach($_LANG['ReviewFields'] as $Key => $Value)
	  {
	  	ValidateReviewInfoFieldValue($PostReviewInfo,$Key,$ActionMsg);
    }
}

function ValidatePostEditReviewInfo($PostReviewInfo,$RawReviewInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostReviewInfo as $Key => $Value)
    {
        if($_LANG['ReviewFields'][$Key])
        {
        		ValidateReviewInfoFieldValue($PostReviewInfo,$Key,$ActionMsg);
        }
    }

    if($PostReviewInfo['ActionType'] == 'Resolved')
    {
        //Check the previos status
        if($RawReviewInfo['ReviewStatus'] == 'Resolved')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyResolved'];
        }
        
        ValidateReviewInfoResolvedFields($PostReviewInfo,$RawReviewInfo,$ActionMsg);        
    }
    elseif($PostReviewInfo['ActionType'] == 'Closed')
    {
        if($RawReviewInfo['ReviewStatus'] == 'Closed')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyClosed'];
        }         
        ValidateReviewInfoResolvedFields($PostReviewInfo,$RawReviewInfo,$ActionMsg);
    }
    elseif($PostReviewInfo['ActionType'] == 'Activated')
    {
        if($RawReviewInfo['ReviewStatus'] == 'Active')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyActive'];
        }
    }
    
    $LastActionID = testGetLastActionID('Review',$PostReviewInfo['ReviewID']);
    if($PostReviewInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['ReviewAlreadyChanged'];
    }
}

function BuildSqlReviewInsertArray($FieldList,$ReviewInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'ReviewID')
			{
					continue;
			}
					
			if(isset($ReviewInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $ReviewInfo[$Key];
			}
	}
}

function InsertReviewInfo($PostReviewInfo)
{   
		global $_LANG;
		
		/* Build ReviewInfo */
		//Get Original PostReviewInfo
		$ReviewInfo = $PostReviewInfo;
		
		//Get CurretnUser and CurrentDate
    $CurrentUser = $PostReviewInfo['TestUserName'];
    $CurrentDate = date('Y-m-d H:i:s');
    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $ReviewInfo['OpenedBy'] = $CurrentUser;	
   	$ReviewInfo['OpenedDate'] = $CurrentDate;
    $ReviewInfo['LastEditedBy'] = $CurrentUser;
   	$ReviewInfo['LastEditedDate'] = $CurrentDate;
    $ReviewInfo['ModifiedBy'] = $CurrentUser;
    
    //Set BugStatus
    if(empty($PostReviewInfo['ReviewStatus']))
    {
    	$ReviewInfo['ReviewStatus'] = 'Active';
    }
 
 		//Create the SqlInsertArray
		$SqlInsertArray = array();
		BuildSqlReviewInsertArray($_LANG['ReviewFields'],$ReviewInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$ReviewID = dbInsertFieldRow('ReviewInfo',$SqlInsertArray);
		
		return $ReviewID;
}

function UpdateOriginalChangeInfo($ChangeID,$ReviewID)
{
		if($ChangeID > 0)
    {
    		$WhereStr = "ChangeID={$ChangeID}";
				$Key = 'ReviewID';
				$Value = "CONCAT(ReviewID,'{$ReviewID}',',')";
        dbUpdateRow('ChangeInfo',$Key,$Value, $WhereStr);
    }
}

function SendOpenReviewNotifyMail($PostReviewInfo,$ReviewID,$ProjectID)
{
		global $_LANG;
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('Review',$PostReviewInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('Review',$PostReviewInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build ReviewMailTitle		
    $ReviewMailTitle = '['.$_LANG['TracSystem'].']'.' IR'.$ReviewID.' was raised: '.$PostReviewInfo['ReviewTitle'];
    
    //Build MainMessage
 		$ActionUser = $PostReviewInfo['TestUserName'];
 		$AssignedTo = $PostReviewInfo['Author'];
 		$MailContent = BuildMailContentForOpenAction($PostReviewInfo,$_LANG['ReviewFields']);
		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($ReviewID,'Opened',$ActionUser,$AssignedTo,$MailContent,'Review');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ReviewMailTitle, $MainMessage);
}

function USSummerTimeCheck($TimeStamp)
{
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		//Get the Year Info
		$Year = date('Y',$TimeStamp);
		
		//Get the TimeStamp For SummerStart and SummerEnd
		$MarchFirstDay = mktime(0,0,0,3,1,$Year);	
		$WeekDay = date('N',$MarchFirstDay);
		Rainy_Debug($WeekDay,__FUNCTION__,__LINE__,__FILE__);
		$SummerStartTimeStamp = $MarchFirstDay + (14-$WeekDay)*24*3600;
		Rainy_Debug($SummerStartTimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		$NovFirstDay = mktime(0,0,0,11,1,$Year);
		$WeekDay = date('N',$NovFirstDay);
		Rainy_Debug($WeekDay,__FUNCTION__,__LINE__,__FILE__);
		$SummerEndTimeStamp = $NovFirstDay + (7-$WeekDay)*24*3600;
		Rainy_Debug($SummerEndTimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		if(($TimeStamp > $SummerStartTimeStamp) && ($TimeStamp < $SummerEndTimeStamp))
		{
			return 1;
		}
		return 0;
}

function TimeConvertFromCNToUS($TimeStamp)
{
		//TracSystem is Using CN TimeZone, Mail Server is Using US TimeZone
		//But the MailServer was unable to know if We told it the TimeZone on Calendar Mail
		//So we try to use a work around way: base on the CN time to caculate the US Time 
		if(USSummerTimeCheck($TimeStamp) == 1)	
		{
				$TimeStamp = $TimeStamp - 13*3600;
		}
		else
		{
				$TimeStamp = $TimeStamp - 14*3600;
		}
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		return $TimeStamp;
}

function GetOpenReviewMeetingStartTime($PostReviewInfo)
{
		global $_LANG;	 
		
		//Get the Date Info
		$MeetingDate = $PostReviewInfo['MeetingDate'];
		$Date = explode('-', $MeetingDate);
		
		//Get the Time Info
		$Time = $PostReviewInfo['StartTime'];
		$Time = $_LANG['TimeList'][$Time];
		$Time = explode(':', $Time);
		$Time[2] = '00';
			
		//Caculate the TimeStamp 
		$TimeStamp = mktime($Time[0],$Time[1],$Time[2],$Date[1],$Date[2],$Date[0]);
		$TimeStamp = TimeConvertFromCNToUS($TimeStamp);
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		$MeetingStartTime = date('Ymd',$TimeStamp)."T".date('His',$TimeStamp);
		Rainy_Debug($MeetingStartTime,__FUNCTION__,__LINE__,__FILE__);
		return $MeetingStartTime;
}

function GetOpenReviewMeetingEndTime($PostReviewInfo)
{
		global $_LANG;
		
		//Get the Date Info
		$MeetingDate = $PostReviewInfo['MeetingDate'];
		$Date = explode('-', $MeetingDate);
		
		//Get the Time Info
		$Time = $PostReviewInfo['EndTime'];
		$Time = $_LANG['TimeList'][$Time];
		$Time = explode(':', $Time);
		$Time[2] = '00';
			
		//Caculate the TimeStamp 
		$TimeStamp = mktime($Time[0],$Time[1],$Time[2],$Date[1],$Date[2],$Date[0]);
		$TimeStamp = TimeConvertFromCNToUS($TimeStamp);
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
				
		$MeetingEndTime = date('Ymd',$TimeStamp)."T".date('His',$TimeStamp);
		Rainy_Debug($MeetingEndTime,__FUNCTION__,__LINE__,__FILE__);
		return $MeetingEndTime;
}

function SendOpenReviewMeetingRequest($PostReviewInfo,$ReviewID,$ProjectID)
{	
		global $_LANG;
		global $_CFG;
		
		//Get Email To and CCList
 		$ToList = GetEmailToListForOpenAction('Review',$PostReviewInfo);
 		$CCList = GetEmailCCListForOpenAction('Review',$PostReviewInfo);
 		Rainy_Debug($ToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($CCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set the Sender: please do not change it
		$Sender['Email'] = $_CFG["Mail"]["FromAddress"];
		$Sender['RealName'] = $_CFG["Mail"]["FromName"];
		Rainy_Debug($Sender,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Set the Organizer
 		//$Author = $PostReviewInfo['Author'];
 		$Author = $PostReviewInfo['TestUserName'];
		$Organizer = testGetUserInfoByName($Author);
		Rainy_Debug($Organizer,__FUNCTION__,__LINE__,__FILE__);
 		
		//Set the Subject
		$Subject= "[".$_LANG['ReviewInvitation']."] ".$PostReviewInfo['ReviewTitle'];
		Rainy_Debug($Subject,__FUNCTION__,__LINE__,__FILE__);
		
		//Set the Message
		//$Message = $_LANG['ReviewFields']['ReviewContent'].":\n";
		//$Message .= GetEditReviewFieldValue('ReviewContent',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)."\n";
		//$Message .= $_LANG['PleaseSubmitReviewCommentHere'].":\n";
		$Message .= GetLinkStr('Review',$ReviewID);
		$Message = addslashes($Message);
		Rainy_Debug($Message,__FUNCTION__,__LINE__,__FILE__);
		 
		//Build ICalendar Arrary
 		$iCalendar['UID'] = $_LANG['ReviewIDPrefix'].(int)$ReviewID;
 		$iCalendar['start'] = GetOpenReviewMeetingStartTime($PostReviewInfo);
 		$iCalendar['end'] = GetOpenReviewMeetingEndTime($PostReviewInfo);
 		$iCalendar['summary'] = $Subject;
 		$iCalendar['location'] = $PostReviewInfo['MeetingLocation'];
 		Rainy_Debug($iCalendar,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Send the ICalendar
 		sendIcal($ToList,$CCList,$Subject, $Message,$Sender, $Organizer,$iCalendar );
}

/**
 * Open Review
 *
 * @author RainyGao <zju_rain@163.com>
 * @param  array  $PostReviewInfo
 * @return array  $ActionMsg
 */
function testOpenReview($PostReviewInfo)
{
		//Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostReviewInfo['ProjectID'];
    $ModuleID = $PostReviewInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
    //Pre-Handler for PostReviewInfo
		PostReviewInfoPreHandler($PostReviewInfo,$ProjectID,$ProjectInfo,$ModulePath);

    /***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Review');		
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenReviewInfo($PostReviewInfo,$ActionMsg);

    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostReviewInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$ReviewID = InsertReviewInfo($PostReviewInfo);
		
		//Update Original ChangeInfo
    UpdateOriginalChangeInfo($PostReviewInfo['ChangeID'],$ReviewID);

    //Insert Post Action
    $ActionID = InsertAddAction($PostReviewInfo,'Review',$ReviewID);

		//SendOpenReviewNotifyMail
		SendOpenReviewNotifyMail($PostReviewInfo,$ReviewID,$ProjectID);
		if($PostReviewInfo['SendMeetingRequest'] == 'SendMeetingRequest')
		{
			SendOpenReviewMeetingRequest($PostReviewInfo,$ReviewID,$ProjectID);
		}
		
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['ReviewID'] = $ReviewID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

/*=== Local APIs for Review Edit Actions ======*/
function GetRawReviewInfo($ReviewID)
{
		$Columns = '*';
  	$RawReviewInfo = dbGetRow('ReviewInfo',$Columns,"ReviewID = '{$ReviewID}'");	
  	return $RawReviewInfo;
}

function GetReviewDiffInfo($PostReviewInfo,$RawReviewInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostReviewInfo = sysStripSlash($PostReviewInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['ReviewFields']);
		$ReviewDiffInfo = array();
    $ReviewDiffInfo += sysArrayDiffAssoc($TempPostReviewInfo, $RawReviewInfo, $DiffAssoc);
		
		//ReviewID should never be changed as ReviewDiffInfo
    if($ReviewDiffInfo['ReviewID'])
    {
    		unset($ReviewDiffInfo['ReviewID']);
    }
    
    return $ReviewDiffInfo;
}

function IsReviewInfoChanged($ReviewDiffInfo,$PostReviewInfo,$UploadFile)
{
		if(!empty($ReviewDiffInfo) || $PostReviewInfo['ReplyNote'] != '' || $UploadFile || $PostReviewInfo['ActionType'] == 'Closed' || $PostReviewInfo['ActionType'] == 'Activated')
    {
			return true;
		}
		return false;
}

function BuildSqlReviewSetArray($FieldList,$ReviewInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//ReviewID should not be Changed
			if($Key == 'ReviewID')
			{
					continue;
			}
			
			if(isset($ReviewInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $ReviewInfo[$Key];
			}
	}		
}

function EditReviewInfo($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)
{
		global $_LANG;
		
		/* Build ReviewInfo */
		//Get Original ReviewDiffInfo
		$ReviewInfo = $ReviewDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostReviewInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
		
		//Set the ReviewStatus ResolvedBy,ClosedBy...
    if($PostReviewInfo['ActionType'] == 'Resolved')
    {
    	  $ReviewInfo['ReviewStatus'] =  'Resolved';
    		$ReviewInfo['ResolvedBy'] =  $CurrentUser;
    		$ReviewInfo['ResolvedDate'] =  $CurrentDate;
    }
    elseif($PostReviewInfo['ActionType'] == 'Closed')
    {
        $ReviewInfo['ReviewStatus'] =  'Closed';
    		$ReviewInfo['ClosedBy'] = $CurrentUser;
    	 	$ReviewInfo['ClosedDate'] = $CurrentDate;
    }
    elseif($PostReviewInfo['ActionType'] == 'Activated')
    {
        $ReviewInfo['ReviewStatus'] =  'Active';
        $ReviewInfo['ResolvedBy'] =  '';
        $ReviewInfo['ResolvedDate'] = '0000-00-00 00:00:00';
        $ReviewInfo['ClosedBy'] =  '';
        $ReviewInfo['ClosedDate'] = '0000-00-00 00:00:00';
    }
    
		//There is nothing to Update
    if(empty($ReviewInfo))
    {
    	 Rainy_Debug("No Fields in ReviewInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $ReviewInfo['LastEditedBy'] = $CurrentUser;
    $ReviewInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$ReviewInfo['ModifiedBy'] = "{$RawReviewInfo[ModifiedBy]},{$ReviewInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined ReviewFields
		$SqlSetArray = array();
		BuildSqlReviewSetArray($_LANG['ReviewFields'],$ReviewInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the ReviewInfo
    dbUpdateFieldRow('ReviewInfo', $SqlSetArray, "ReviewID='{$ReviewID}'");
}

function SendEditReviewNotifyMail($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('Review',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('Review',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostReviewInfo['ActionType'];
    Rainy_Debug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set ReviewMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] IR'.$ReviewID.' was '.$ActionType.': ';
    $ReviewMailTitle = $MailPrefix.$PostReviewInfo['ReviewTitle'];
    Rainy_Debug($ReviewMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostReviewInfo['TestUserName'];
 		$AssignedTo = $PostReviewInfo['Author'];
    $MailContent = BuildMailContentForEditAction($PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo,$_LANG['ReviewFields']);
    Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($ReviewID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'Review', $ActionDesc);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ReviewMailTitle, $MainMessage);
}

function SendEditReviewMeetingRequest($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)
{	
		global $_LANG;
		global $_CFG;
		
		//If Meeting Location and  Time Not Changed, Need not to Send the Meeting Request
		if(empty($ReviewDiffInfo['MeetingLocation']) && empty($ReviewDiffInfo['MeetingDate']) && empty($ReviewDiffInfo['StartTime']) && empty($ReviewDiffInfo['EndTime'])) 
		{
				return;
		}
		
		//Get the To and CCList		
 		$ToList = GetEmailToListForEditAction('Review',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		$CCList = GetEmailCCListForEditAction('Review',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		Rainy_Debug($ToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($CCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set the Sender: please do not change it
		$Sender['Email'] = $_CFG["Mail"]["FromAddress"];
		$Sender['RealName'] = $_CFG["Mail"]["FromName"];
		Rainy_Debug($Sender,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Set the Organizer
 		//$Author = GetEditReviewFieldValue('Author',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		$Author = $PostReviewInfo['TestUserName'];
		$Organizer = testGetUserInfoByName($Author);
		Rainy_Debug($Organizer,__FUNCTION__,__LINE__,__FILE__);
 		
 		
		//Set the Subject
		$Subject= "[".$_LANG['ReviewInvitation']."] ".GetEditReviewFieldValue('ReviewTitle',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		Rainy_Debug($Subject,__FUNCTION__,__LINE__,__FILE__);
		
		//Set the Message
		//$Message = $_LANG['ReviewFields']['ReviewContent'].":\n";
		//$Message .= GetEditReviewFieldValue('ReviewContent',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)."\n";
		//$Message .= $_LANG['PleaseSubmitReviewCommentHere'].":\n";
		$Message .= GetLinkStr('Review',$ReviewID);
		$Message = addslashes($Message);
		Rainy_Debug($Message,__FUNCTION__,__LINE__,__FILE__);
		 
		//Build ICalendar Arrary
 		$iCalendar['UID'] = $_LANG['ReviewIDPrefix'].(int)$ReviewID;
 		$iCalendar['start'] = GetEditReviewMeetingStartTime($PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		$iCalendar['end'] = GetEditReviewMeetingEndTime($PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		$iCalendar['summary'] = $Subject;
 		$iCalendar['location'] = GetEditReviewFieldValue('MeetingLocation',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
 		Rainy_Debug($iCalendar,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Send the ICalendar
 		sendIcal($ToList,$CCList,$Subject, $Message,$Sender, $Organizer,$iCalendar );
}

function GetEditReviewFieldValue($FieldName,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)
{
		if(empty($ReviewDiffInfo[$FieldName]))
		{
			$Value = $RawReviewInfo[$FieldName];
		}
		else
		{
			$Value = $PostReviewInfo[$FieldName];
		}
		return $Value;
}

function GetEditReviewMeetingStartTime($PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)
{
		global $_LANG;	 
		
		//Build the Meeting DateStr For iCalendar
		$MeetingDate = GetEditReviewFieldValue('MeetingDate',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		$Date = explode('-', $MeetingDate);
		
		//Build the Meeting StartTimeStr For iCalendar
		$Time = GetEditReviewFieldValue('StartTime',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		$Time = $_LANG['TimeList'][$Time];
		$Time = explode(':', $Time);
		$Time[2] = '00';
			
		//Caculate the TimeStamp 
		$TimeStamp = mktime($Time[0],$Time[1],$Time[2],$Date[1],$Date[2],$Date[0]);
		$TimeStamp = TimeConvertFromCNToUS($TimeStamp);
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
		
		$MeetingStartTime = date('Ymd',$TimeStamp)."T".date('His',$TimeStamp);
		Rainy_Debug($MeetingStartTime,__FUNCTION__,__LINE__,__FILE__);
		return $MeetingStartTime;
}

function GetEditReviewMeetingEndTime($PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo)
{
		global $_LANG;
		
		//Build the Meeting DateStr For iCalendar
		$MeetingDate = GetEditReviewFieldValue('MeetingDate',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		$Date = explode('-', $MeetingDate);
		
		//Build the Meeting StartTimeStr For iCalendar
		$Time = GetEditReviewFieldValue('EndTime',$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		$Time = $_LANG['TimeList'][$Time];
		$Time = explode(':', $Time);
		$Time[2] = '00';
			
		//Caculate the TimeStamp 
		$TimeStamp = mktime($Time[0],$Time[1],$Time[2],$Date[1],$Date[2],$Date[0]);
		$TimeStamp = TimeConvertFromCNToUS($TimeStamp);
		Rainy_Debug($TimeStamp,__FUNCTION__,__LINE__,__FILE__);
				
		$MeetingEndTime = date('Ymd',$TimeStamp)."T".date('His',$TimeStamp);
		Rainy_Debug($MeetingEndTime,__FUNCTION__,__LINE__,__FILE__);
		return $MeetingEndTime;
}

/**
 * Edit Review
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostReviewInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditReview($PostReviewInfo, $UploadFile = false)
{
    global $_LANG;
    
    //Get ReviewID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $ReviewID = $PostReviewInfo['ReviewID'];
		$ProjectID = $PostReviewInfo['ProjectID'];
    $ModuleID = $PostReviewInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostReviewInfo
		PostReviewInfoPreHandler($PostReviewInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_Debug($PostReviewInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Review',$ReviewID);
		
		//Get RawReviewInfo
    $RawReviewInfo = GetRawReviewInfo($ReviewID);
		//Rainy_Debug($PostReviewInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Validate PostReviewInfo
		ValidatePostEditReviewInfo($PostReviewInfo,$RawReviewInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostReviewInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }
	  
		//GetReviewDiffInfo
		$ReviewDiffInfo = GetReviewDiffInfo($PostReviewInfo,$RawReviewInfo,$ProjectInfo,$ModulePath);
		//Rainy_Debug($ReviewDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update ReviewInfo
		EditReviewInfo($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);

		//Check if ReviewInfo was changed
    if(IsReviewInfoChanged($ReviewDiffInfo,$PostReviewInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    $ActionID = InsertEditAction($PostReviewInfo,'Review',$ReviewID);

    //Add the Histroy Info to the EditAction
    InsertEditHistoryInfo($ActionID,$RawReviewInfo,$ReviewDiffInfo);
    
		//Send Notify Email
		Rainy_Debug($PostReviewInfo['SendNotifyEmail'],__FUNCTION__,__LINE__,__FILE__);
		if($PostReviewInfo['SendNotifyEmail'] == 'SendNotifyEmail')
		{
			SendEditReviewNotifyMail($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo,$UploadFile);
		}
		if($PostReviewInfo['SendMeetingRequest'] == 'SendMeetingRequest')
		{
			SendEditReviewMeetingRequest($ReviewID,$PostReviewInfo,$RawReviewInfo,$ReviewDiffInfo);
		}
		
		$ActionMsg['ActionID'] = $ActionID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for ReviewComment Open Actions ======*/
function PostReviewCommentInfoPreHandler(&$PostReviewCommentInfo,$ProjectID)
{
		global $_LANG;
		
		//Get ReviewInfo
		$ReviewInfo = GetRawReviewInfo($PostReviewCommentInfo['ReviewID']);
		$ProjectID = $ReviewInfo['ProjectID'];
		
		//Set ProjectName and ModulePath
  	$PostReviewCommentInfo['ProjectID'] = $ReviewInfo['ProjectID'];
    $PostReviewCommentInfo['ProjectName'] = $ReviewInfo['ProjectName'];
    $PostReviewCommentInfo['ModuleID'] = $ReviewInfo['ModuleID'];
    $PostReviewCommentInfo['ModulePath'] = $ReviewInfo['ModulePath'];
		
		//Set ReviewType and ReviewCommentPos1Name
		$ReviewType = $ReviewInfo['ReviewType'];
    $PostReviewCommentInfo['ReviewType'] = $ReviewType;
    $PostReviewCommentInfo['ReviewCommentPos1Name'] = $_LANG['ReviewCommentPos1Names'][$ReviewType];
    $PostReviewCommentInfo['ReviewCommentPos2Name'] = $_LANG['ReviewCommentPos2Names'][$ReviewType];
    $PostReviewCommentInfo['ReviewCommentPos3Name'] = $_LANG['ReviewCommentPos3Names'][$ReviewType]; 

		/* Do String Convert */    
    foreach($PostReviewCommentInfo as $Key => $Value)
    {
        if($_LANG['ReviewCommentFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'ReviewCommentTitle':
                	$PostReviewCommentInfo['ReviewCommentTitle'] = sysDbSubStr(htmlspecialchars($PostReviewCommentInfo['ReviewCommentTitle']),150);
                	break;     
                case 'MailTo':
                	$MailToList = testGetMailToList(sysStripSlash($PostReviewCommentInfo['MailTo']), $ProjectID, true);
                	$PostReviewCommentInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
            }
        }
    }
    
    //ReplyNote Convert
		if(!empty($PostReviewCommentInfo['ReplyNote'])) 
		{   
    	$PostReviewCommentInfo['ReplyNote'] = htmlspecialchars($PostReviewCommentInfo['ReplyNote']);
    }
}

function ValidateReviewCommentInfoFieldValue($PostReviewCommentInfo,$Key,&$ActionMsg)
{
		global $_LANG;
		
		switch($Key)
  	{
  	case 'ProjectID':
		case 'ProjectName':
		case 'ModuleID':
		case 'ModulePath':
  	case 'ReviewCommentTitle':
		case 'ReviewCommentType':
		//case 'ReviewCommentStatus':
		//case 'ReviewCommentContent':
		case 'ReviewCommentOwner':		
				if($PostReviewCommentInfo[$Key] == '')
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
        break;
    case 'ReviewCommentPos1':
    		if($PostReviewCommentInfo[$Key] == '')
  	    {
  	    	$ReviewType = $PostReviewCommentInfo['ReviewType'];
  	    	Rainy_Debug($ReviewType,__FUNCTION__,__LINE__,__FILE__);
    	  	$ActionMsg['FailedMsg'][] = $_LANG['Position1ErrorMsg'][$ReviewType];
      	}
        break;
    case 'ReviewCommentPos2':
    		if($PostReviewCommentInfo[$Key] == '')
  	    {
  	    	$ReviewType = $PostReviewCommentInfo['ReviewType'];
    	  	$ActionMsg['FailedMsg'][] = $_LANG['Position2ErrorMsg'][$ReviewType];
      	}
        break;
    case 'ReviewCommentPos3':
    		if($PostReviewCommentInfo[$Key] == '')
  	    {
  	    	$ReviewType = $PostReviewCommentInfo['ReviewType'];
    	  	$ActionMsg['FailedMsg'][] = $_LANG['Position3ErrorMsg'][$ReviewType];
      	}
        break;
  	}			
}

function ValidateReviewCommentInfoResolvedFields($PostReviewCommentInfo,&$ActionMsg)
{
		global $_LANG;
		//ResolvedBuild Check
    if(empty($PostReviewCommentInfo['Resolution']))
    {
    	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg']['Resolution'];
    }
}

function ValidatePostOpenReviewCommentInfo($PostReviewCommentInfo,&$ActionMsg)
{		
		global $_LANG;
	  
	  foreach($_LANG['ReviewCommentFields'] as $Key => $Value)
	  {
	  	ValidateReviewCommentInfoFieldValue($PostReviewCommentInfo,$Key,$ActionMsg);
    }
}

function ValidatePostEditReviewCommentInfo($PostReviewCommentInfo,$RawReviewCommentInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostReviewCommentInfo as $Key => $Value)
    {
        if($_LANG['ReviewCommentFields'][$Key])
        {
        		ValidateReviewCommentInfoFieldValue($PostReviewCommentInfo,$Key,$ActionMsg);
        }
    }

    if($PostReviewCommentInfo['ActionType'] == 'Resolved')
    {
        //Check the previos status
        if($RawReviewCommentInfo['ReviewCommentStatus'] == 'Resolved')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyResolved'];
        }
        
        ValidateReviewCommentInfoResolvedFields($PostReviewCommentInfo,$ActionMsg);        
    }
    elseif($PostReviewCommentInfo['ActionType'] == 'Closed')
    {
        if($RawReviewCommentInfo['ReviewCommentStatus'] == 'Closed')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyClosed'];
        }         
        ValidateReviewCommentInfoResolvedFields($PostReviewCommentInfo,$ActionMsg);
    }
    elseif($PostReviewCommentInfo['ActionType'] == 'Activated')
    {
        if($RawReviewCommentInfo['ReviewCommentStatus'] == 'Active')
        {
            $ActionMsg['FailedMsg'][] = $_LANG['AlreadyActive'];
        }
    }
    
    $LastActionID = testGetLastActionID('ReviewComment',$PostReviewCommentInfo['ReviewCommentID']);
    if($PostReviewCommentInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['ReviewCommentAlreadyChanged'];
    }
}

function BuildSqlReviewCommentInsertArray($FieldList,$ReviewCommentInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'ReviewCommentID')
			{
					continue;
			}
					
			if(isset($ReviewCommentInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $ReviewCommentInfo[$Key];
			}
	}
}

function InsertReviewCommentInfo($PostReviewCommentInfo)
{
		global $_LANG;
		
		/* Build ReviewCommentInfo */
		//Get Original PostReviewInfo
		$ReviewCommentInfo = $PostReviewCommentInfo;
		
		//Get CurretnUser and CurrentDate
    $CurrentUser = $PostReviewCommentInfo['TestUserName'];
    $CurrentDate = date('Y-m-d H:i:s');
    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $ReviewCommentInfo['OpenedBy'] = $CurrentUser;	
   	$ReviewCommentInfo['OpenedDate'] = $CurrentDate;
    $ReviewCommentInfo['LastEditedBy'] = $CurrentUser;
   	$ReviewCommentInfo['LastEditedDate'] = $CurrentDate;
    $ReviewCommentInfo['ModifiedBy'] = $CurrentUser;
    
    //Set BugStatus
    if(empty($PostReviewCommentInfo['ReviewCommentStatus']))
    {
    	$ReviewCommentInfo['ReviewCommentStatus'] = 'Active';
    }
 
 		//Create the SqlInsertArray
		$SqlInsertArray = array();
		BuildSqlReviewCommentInsertArray($_LANG['ReviewCommentFields'],$ReviewCommentInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$ReviewCommentID = dbInsertFieldRow('ReviewCommentInfo',$SqlInsertArray);
		
		return $ReviewCommentID;
}


function UpdateOriginalReviewInfo($ReviewID,$ReviewCommentID)
{
		if($ReviewID > 0)
    {
    		$WhereStr = "ReviewID={$ReviewID}";
				$Key = 'ReviewCommentID';
				$Value = "CONCAT(ReviewCommentID,'{$ReviewCommentID}',',')";
        dbUpdateRow('ReviewInfo',$Key,$Value, $WhereStr);
    }
}

function SendOpenReviewCommentNotifyMail($PostReviewCommentInfo,$ReviewCommentID,$ProjectID)
{
		global $_LANG;
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('ReviewComment',$PostReviewCommentInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('ReviewComment',$PostReviewCommentInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build ReviewCommentMailTitle		
    $ReviewCommentMailTitle = '['.$_LANG['TracSystem'].']'.' ReviewComment'.$ReviewCommentID.' was raised: '.$PostReviewCommentInfo['ReviewCommentTitle'];
    Rainy_Debug($ReviewCommentMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Build MainMessage
 		$ActionUser = $PostReviewCommentInfo['TestUserName'];
 		$AssignedTo = $PostReviewCommentInfo['AssignedTo'];
 		$MailContent = BuildMailContentForOpenAction($PostReviewCommentInfo,$_LANG['ReviewCommentFields']);
 		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($ReviewCommentID,'Opened',$ActionUser,$AssignedTo,$MailContent,'ReviewComment');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ReviewCommentMailTitle, $MainMessage);
}

/**
 * Open ReviewComment
 *
 * @author RainyGao <zju_rain@163.com>
 * @param  array  $PostReviewCommentInfo
 * @return array  $ActionMsg
 */
function testOpenReviewComment($PostReviewCommentInfo)
{   
		//Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostReviewCommentInfo['ProjectID'];
    $ModuleID = $PostReviewCommentInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
    //Pre-Handler for PostReviewCommentInfo
		PostReviewCommentInfoPreHandler($PostReviewCommentInfo,$ProjectID,$ProjectInfo,$ModulePath);
		Rainy_Debug($PostReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__);

    /***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('ReviewComment');		
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenReviewCommentInfo($PostReviewCommentInfo,$ActionMsg);

    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__,1);	
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$ReviewCommentID = InsertReviewCommentInfo($PostReviewCommentInfo);
		
		//Update Original ReviewInfo
    UpdateOriginalReviewInfo($PostReviewCommentInfo['ReviewID'],$ReviewCommentID);

    //Insert Post Action
    //$ActionID = InsertAddAction($PostReviewCommentInfo,'ReviewComment',$ReviewCommentID);
	
		SendOpenReviewCommentNotifyMail($PostReviewCommentInfo,$ReviewCommentID,$ProjectID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['ReviewCommentID'] = $ReviewCommentID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

/*=== Local APIs for ReviewComment Edit Actions ======*/
function GetRawReviewCommentInfo($ReviewCommentID)
{
		$Columns = '*';
  	$RawReviewCommentInfo = dbGetRow('ReviewCommentInfo',$Columns,"ReviewCommentID = '{$ReviewCommentID}'");	
  	return $RawReviewCommentInfo;
}

function GetReviewCommentDiffInfo($PostReviewCommentInfo,$RawReviewCommentInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostReviewCommentInfo = sysStripSlash($PostReviewCommentInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['ReviewCommentFields']);
		$ReviewCommentDiffInfo = array();
    $ReviewCommentDiffInfo += sysArrayDiffAssoc($TempPostReviewCommentInfo, $RawReviewCommentInfo, $DiffAssoc);
		
		//ReviewCommentID should never be changed as ReviewCommentDiffInfo
    if($ReviewCommentDiffInfo['ReviewCommentID'])
    {
    		unset($ReviewCommentDiffInfo['ReviewCommentID']);
    }
    
    return $ReviewCommentDiffInfo;
}

function IsReviewCommentInfoChanged($ReviewCommentDiffInfo,$PostReviewCommentInfo,$UploadFile)
{
		if(!empty($ReviewCommentDiffInfo) || $PostReviewCommentInfo['ReplyNote'] != '' || $UploadFile || $PostReviewCommentInfo['ActionType'] == 'Closed' || $PostReviewCommentInfo['ActionType'] == 'Activated')
    {
			return true;
		}
		return false;
}

function BuildSqlReviewCommentSetArray($FieldList,$ReviewCommentInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//ReviewCommentID should not be Changed
			if($Key == 'ReviewCommentID')
			{
					continue;
			}
			
			if(isset($ReviewCommentInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $ReviewCommentInfo[$Key];
			}
	}		
}

function EditReviewCommentInfo($ReviewCommentID,$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo)
{
		global $_LANG;
		
		/* Build ReviewCommentInfo */
		//Get Original ReviewCommentDiffInfo
		$ReviewCommentInfo = $ReviewCommentDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostReviewCommentInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
		
		//Set the ReviewCommentStatus ResolvedBy,ClosedBy...
    if($PostReviewCommentInfo['ActionType'] == 'Resolved')
    {
    	  $ReviewCommentInfo['ReviewCommentStatus'] =  'Resolved';
    		$ReviewCommentInfo['ResolvedBy'] =  $CurrentUser;
    		$ReviewCommentInfo['ResolvedDate'] =  $CurrentDate;
    }
    elseif($PostReviewCommentInfo['ActionType'] == 'Closed')
    {
        $ReviewCommentInfo['ReviewCommentStatus'] =  'Closed';
    		$ReviewCommentInfo['ClosedBy'] = $CurrentUser;
    	 	$ReviewCommentInfo['ClosedDate'] = $CurrentDate;
    }
    elseif($PostReviewCommentInfo['ActionType'] == 'Activated')
    {
        $ReviewCommentInfo['ReviewCommentStatus'] =  'Active';
        $ReviewCommentInfo['ResolvedBy'] =  '';
        $ReviewCommentInfo['ResolvedDate'] = '0000-00-00 00:00:00';
        $ReviewCommentInfo['ClosedBy'] =  '';
        $ReviewCommentInfo['ClosedDate'] = '0000-00-00 00:00:00';
    }
    
		//There is nothing to Update
    if(empty($ReviewCommentInfo))
    {
    	 Rainy_Debug("No Fields in ReviewCommentInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $ReviewCommentInfo['LastEditedBy'] = $CurrentUser;
    $ReviewCommentInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$ReviewCommentInfo['ModifiedBy'] = "{$RawReviewCommentInfo[ModifiedBy]},{$ReviewCommentInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined ReviewCommentFields
		$SqlSetArray = array();
		BuildSqlReviewCommentSetArray($_LANG['ReviewCommentFields'],$ReviewCommentInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the ReviewCommentInfo
    dbUpdateFieldRow('ReviewCommentInfo', $SqlSetArray, "ReviewCommentID='{$ReviewCommentID}'");
}

function SendEditReviewCommentNotifyMail($ReviewCommentID,$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('ReviewComment',$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('ReviewComment',$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostReviewCommentInfo['ActionType'];
    Rainy_Debug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set ReviewCommentMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] ReviewComment'.$ReviewCommentID.' was '.$ActionType.': ';
    $ReviewCommentMailTitle = $MailPrefix.$PostReviewCommentInfo['ReviewCommentTitle'];
    Rainy_Debug($ReviewCommentMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostReviewCommentInfo['TestUserName'];
 		$AssignedTo = $PostReviewCommentInfo['AssignedTo'];
    $MailContent = BuildMailContentForEditAction($PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo,$_LANG['ReviewCommentFields']);
    $MainMessage = testCreateMailMessage($ReviewCommentID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'ReviewComment');
    Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $ReviewCommentMailTitle, $MainMessage);
}

/**
 * Edit ReviewComment
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostReviewCommentInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditReviewComment($PostReviewCommentInfo, $UploadFile = false)
{
    global $_LANG;
    
    //Get ReviewCommentID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $ReviewCommentID = $PostReviewCommentInfo['ReviewCommentID'];
		$ProjectID = $PostReviewCommentInfo['ProjectID'];
    $ModuleID = $PostReviewCommentInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostReviewCommentInfo
		PostReviewCommentInfoPreHandler($PostReviewCommentInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_Debug($PostReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('ReviewComment',$ReviewCommentID);
		
		//Get RawReviewCommentInfo
    $RawReviewCommentInfo = GetRawReviewCommentInfo($ReviewCommentID);
		//Rainy_Debug($PostReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Validate PostReviewCommentInfo
		ValidatePostEditReviewCommentInfo($PostReviewCommentInfo,$RawReviewCommentInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }
	  
		//GetReviewCommentDiffInfo
		$ReviewCommentDiffInfo = GetReviewCommentDiffInfo($PostReviewCommentInfo,$RawReviewCommentInfo,$ProjectInfo,$ModulePath);
		//Rainy_Debug($ReviewCommentDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update ReviewCommentInfo
		EditReviewCommentInfo($ReviewCommentID,$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo);

		//Check if ReviewCommentInfo was changed
    if(IsReviewCommentInfoChanged($ReviewCommentDiffInfo,$PostReviewCommentInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    //$ActionID = InsertEditAction($PostReviewCommentInfo,'ReviewComment',$ReviewCommentID);

    //Add the Histroy Info to the EditAction
    //InsertEditHistoryInfo($ActionID,$RawReviewCommentInfo,$ReviewCommentDiffInfo);
    
		//Send Notify Email
		SendEditReviewCommentNotifyMail($ReviewCommentID,$PostReviewCommentInfo,$RawReviewCommentInfo,$ReviewCommentDiffInfo,$UploadFile);
		
		$ActionMsg['ActionID'] = $ActionID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for Plan Open Actions ======*/
function PostPlanInfoPreHandler(&$PostPlanInfo,$ProjectID,$ProjectInfo,$ModulePath)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostPlanInfo as $Key => $Value)
    {
        if($_LANG['PlanFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                Case 'PlanTitle':
                	$PostPlanInfo[$Key] = sysDbSubStr(htmlspecialchars($PostPlanInfo['PlanTitle']), 150);
                	break;
         				
								Case 'PlanContent':
 									//textfield format data convert
                	$PostPlanInfo[$Key] = htmlspecialchars($PostPlanInfo[$Key]);
                	break;
             			
             		Case 'PlanStartDate':
                Case 'PlanEndDate':
                		$PostPlanInfo[$Key] = trim($PostPlanInfo[$Key]);
                	break;   
                	                
                Case 'MailTo':
                	$MailToList = testGetMailToList(sysStripSlash($PostPlanInfo['MailTo']), $ProjectID, true);
                	$PostPlanInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
                
                Case 'PlanKeyword':
									//input text format data convert
                	$PostPlanInfo[$Key] = htmlspecialchars(trim($PostPlanInfo[$Key]));
                	break;

            }
        }
    }
    
    
    //Set ProjectName and ModulePath
    if(isset($PostPlanInfo['ProjectID']))
    {
    	$PostPlanInfo['ProjectName'] = $ProjectInfo['ProjectName'];
    }

    if(isset($PostPlanInfo['ModuleID']))
    {
    	$PostPlanInfo['ModulePath'] = $ModulePath;
		}
		
		if(!empty($PostPlanInfo['ReplyNote'])) 
		{   
    	$PostPlanInfo['ReplyNote'] = htmlspecialchars(trim($PostPlanInfo['ReplyNote']));
    }
    
}

function ValidatePlanInfoFieldValue($PostPlanInfo,$Key,&$ActionMsg)
{
		 global $_LANG;
		 switch($Key)
	   {
        		Case 'ProjectID':
						Case 'ProjectName':
						//Case 'ModuleID':
						Case 'ModulePath':
	  				Case 'PlanTitle':
	  				Case 'PlanType':
	  				Case 'PlanBuild':
	  				Case 'PlanContent':
	  				Case 'PlanStartDate':
	  				Case 'PlanEndDate':
	  				//Case 'AssignedTo':
	  					if($PostPlanInfo[$Key] == '')
    					{
        				$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
    					}
	  					break;
	  				Case 'PlanStartDate':
    				Case 'PlanEndDate':
    					if($PostPlanInfo[$Key] != '' && !sysCheckDateFormat($PostPlanInfo[$Key]))
    					{
        					$ActionMsg['FailedMsg'][] = $_LANG['BadScriptedDate'];
    					}
        			break;
     }
}

function ValidatePostOpenPlanInfo($PostPlanInfo,&$ActionMsg)
{		
		global $_LANG;
	  foreach($_LANG['PlanFields'] as $Key => $Value)
	  {
	  		ValidatePlanInfoFieldValue($PostPlanInfo,$Key,$ActionMsg);
    }
}

function BuildSqlPlanInsertArray($FieldList,$PlanInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//PlanID should not be Changed
			if($Key == 'PlanID')
			{
					continue;
			}
					
			if(isset($PlanInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $PlanInfo[$Key];
			}
	}
}

function InsertPlanInfo($PostPlanInfo)
{
		global $_LANG;

    //Get CurrentUser and CurrentDate
		$CurrentUser = $PostPlanInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');

    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $PostPlanInfo['OpenedBy'] = $CurrentUser;	
   	$PostPlanInfo['OpenedDate'] = $CurrentDate;
    $PostPlanInfo['LastEditedBy'] = $CurrentUser;
   	$PostPlanInfo['LastEditedDate'] = $CurrentDate;
    $PostPlanInfo['ModifiedBy'] = $CurrentUser;
		
		//Set AssignedDate
    if($PostPlanInfo['AssignedTo'] != '')
    {
        $AssignDate = $CurrentDate;
    }
    else
    {
        $AssignDate = '';
    }
 		$PostPlanInfo['AssignedDate'] = $AssignDate;		
	  
	  //Set PlanStatus
	  if($PostPlanInfo['PlanStatus']===NULL) 
	  {
	  		$PostPlanInfo['PlanStatus']='Active';
		}
									
		//Get Original PostPlanInfo
		$PlanInfo = $PostPlanInfo;
		//Create the ValueSqlString and KeySqlString
		$SqlInsertArray = array();
		BuildSqlPlanInsertArray($_LANG['PlanFields'],$PlanInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$PlanID = dbInsertFieldRow('PlanInfo',$SqlInsertArray);
		
		return $PlanID;
}

function SendOpenPlanNotifyMail($PostPlanInfo,$PlanID,$ProjectID)
{
		global $_LANG;
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('Plan',$PostPlanInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('Plan',$PostPlanInfo);
 		Rainy_DeBug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build PlanMailTitle		
    $PlanMailTitle = '['.$_LANG['TracSystem'].']'.' Plan'.$PlanID.' was raised: '.$PostPlanInfo['PlanTitle'];
    Rainy_Debug($PlanMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Build MainMessage
 		$ActionUser = $PostPlanInfo['TestUserName'];
 		$AssignedTo = $PostPlanInfo['AssignedTo'];
 		$MailContent = BuildMailContentForOpenAction($PostPlanInfo,$_LANG['PlanFields']);
 		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($PlanID,'Opened',$ActionUser,$AssignedTo,$MailContent,'Plan');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $PlanMailTitle, $MainMessage);
}

/**
 * Open Plan
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostPlanInfo
 * @return array  $ActionMsg
 */
function testOpenPlan($PostPlanInfo)
{	   
    //Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostPlanInfo['ProjectID'];
    $ModuleID = $PostPlanInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);

   	//Pre-Handler for PostPlanInfo
		PostPlanInfoPreHandler($PostPlanInfo,$ProjectID,$ProjectInfo,$ModulePath);

		/***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Plan');	
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenPlanInfo($PostPlanInfo,$ActionMsg);
 
    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_DeBug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_DeBug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_DeBug($PostPlanInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$PlanID = InsertPlanInfo($PostPlanInfo);
		$PostPlanInfo['PlanID'] = $PlanID;

    //Insert Post Action
    $ActionID = InsertAddAction($PostPlanInfo,'Plan',$PlanID);

		//SendOpenPlanNotifyMail
		SendOpenPlanNotifyMail($PostPlanInfo,$PlanID,$ProjectID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['PlanID'] = $PlanID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

function GetRawPlanInfo($PlanID)
{
		$Columns = '*';
  	$RawPlanInfo = dbGetRow('PlanInfo',$Columns,"PlanID = '{$PlanID}'");	
  	return $RawPlanInfo;
}

function ValidatePostEditPlanInfo($PostPlanInfo,$RawPlanInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostPlanInfo as $Key => $Value)
    {
        if($_LANG['PlanFields'][$Key])
       	{
						ValidatePlanInfoFieldValue($PostPlanInfo,$Key,$ActionMsg);
        }
    } 

    $LastActionID = testGetLastActionID('Plan',$PostPlanInfo['PlanID']);
    if($PostPlanInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['PlanAlreadyChanged'];
    }
}

function GetPlanDiffInfo($PostPlanInfo,$RawPlanInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostPlanInfo = sysStripSlash($PostPlanInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['PlanFields']);
		$PlanDiffInfo = array();
    $PlanDiffInfo += sysArrayDiffAssoc($TempPostPlanInfo, $RawPlanInfo, $DiffAssoc);
		
		//PlanID should never be changed as PlanDiffInfo
    if($PlanDiffInfo['PlanID'])
    {
    		unset($PlanDiffInfo['PlanID']);
    }
    
    return $PlanDiffInfo;
}

function EditPlanInfo($PlanID,$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo)
{
		global $_LANG;
		
		/* Build PlanInfo */
		//Get Original PlanDiffInfo
		$PlanInfo = $PlanDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostPlanInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
    
		//There is nothing to Update
    if(empty($PlanInfo))
    {
    	 Rainy_Debug("No Field in PlanInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $PlanInfo['LastEditedBy'] = $CurrentUser;
    $PlanInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$PlanInfo['ModifiedBy'] = "{$RawPlanInfo[ModifiedBy]},{$PlanInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined PlanFields
		$SqlSetArray = array();
		BuildSqlSetArray($_LANG['PlanFields'],$PlanInfo,$SqlSetArray);
		Rainy_DeBug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the PlanInfo
    dbUpdateFieldRow('PlanInfo', $SqlSetArray, "PlanID='{$PlanID}'");
}

function IsPlanInfoChanged($PlanDiffInfo,$PostPlanInfo,$UploadFile)
{
		if(!empty($PlanDiffInfo) || $PostPlanInfo['ReplyNote'] != '' || $UploadFile)
    {
			return true;
		}
		return false;
}

function SendEditPlanNotifyMail($PlanID,$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('Plan',$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('Plan',$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo);
 		Rainy_DeBug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_DeBug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostPlanInfo['ActionType'];
    Rainy_DeBug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set PlanMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] Plan'.$PlanID.' was '.$ActionType.': ';
    $PlanMailTitle = $MailPrefix.$PostPlanInfo['PlanTitle'];
    Rainy_DeBug($PlanMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostPlanInfo['TestUserName'];
 		$AssignedTo = $PostPlanInfo['AssignedTo'];
    $MailContent = BuildMailContentForEditAction($PostPlanInfo,$RawPlanInfo,$PlanDiffInfo,$_LANG['PlanFields']);
    $MainMessage = testCreateMailMessage($PlanID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'Plan');
    Rainy_DeBug($MailContent,__FUNCTION__,__LINE__,__FILE__);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_DeBug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $PlanMailTitle, $MainMessage);
}

/**
 * Edit Plan
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $EditPlanInfo
 * @param  bool   $UploadFile   Upload file or not
 * @return array  $ActionMsg
 */
function testEditPlan($PostPlanInfo, $UploadFile = false)
{
    global $_LANG;
    
    Rainy_DeBug($PostPlanInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Get PlanID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $PlanID = $PostPlanInfo['PlanID'];
		
    //Get RawPlanInfo
    $RawPlanInfo = GetRawPlanInfo($PlanID);
		
		//ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostPlanInfo['ProjectID'];
    $ModuleID = $PostPlanInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostPlanInfo
		PostPlanInfoPreHandler($PostPlanInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_DeBug($PostPlanInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Plan',$PlanID);
		
		//Validate PostPlanInfo
		ValidatePostEditPlanInfo($PostPlanInfo,$RawPlanInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_DeBug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_DeBug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_DeBug($PostPlanInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }
	  
		//GetPlanDiffInfo
		$PlanDiffInfo = GetPlanDiffInfo($PostPlanInfo,$RawPlanInfo,$ProjectInfo,$ModulePath);
		Rainy_DeBug($PlanDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update PlanInfo
		EditPlanInfo($PlanID,$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo);

		//Check if PlanInfo was changed
    if(IsPlanInfoChanged($PlanDiffInfo,$PostPlanInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    $ActionID = InsertEditAction($PostPlanInfo,'Plan',$PlanID);

    //Add the Histroy Info to the EditAction
    InsertEditHistoryInfo($ActionID,$RawPlanInfo,$PlanDiffInfo);
    
		//Send Notify Email
		Rainy_DeBug($PostPlanInfo['SendNotifyEmail'],__FUNCTION__,__LINE__,__FILE__);
		if($PostPlanInfo['SendNotifyEmail'] == 'SendNotifyEmail')
		{
			SendEditPlanNotifyMail($PlanID,$PostPlanInfo,$RawPlanInfo,$PlanDiffInfo,$UploadFile);
		}
		
		$ActionMsg['ActionID'] = $ActionID;
		$ActionMsg['PlanID'] = $PlanID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for User Open Actions ======*/
function PostUserInfoPreHandler(&$PostUserInfo)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostUserInfo as $Key => $Value)
    {
        if($_LANG['UserFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'UserName':
               	case 'RealName':
                	$PostUserInfo[$Key] = htmlspecialchars(trim($PostUserInfo[$Key]));
                	break;
               	case 'Email':
                	$PostUserInfo[$Key] = trim($PostUserInfo[$Key]);
                	break;
                case 'UserPassword':
                	$PostUserInfo['PlainUserPassword'] = $PostUserInfo[$Key];
                	$PostUserInfo[$Key] = baseEncryptUserPWD($PostUserInfo[$Key]);
                	break;
            }
        }
    }
    //Set NoticeFlag as receive email
    $PostUserInfo['NoticeFlag'] = 2;
    
}

function PostUserInfoPreHandler2(&$PostUserInfo)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostUserInfo as $Key => $Value)
    {
        if($_LANG['UserFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'UserPassword':
                	$PostUserInfo['PlainUserPassword'] = $PostUserInfo[$Key];
                	break;
            }
        }
    }
}

function ValidateUserInfoFieldValue($PostUserInfo,$Key,&$ActionMsg)
{
		global $_LANG;
		switch($Key)
  	{
		case 'UserPassword':
		case 'NoticeFlag':
		case 'AuthMode':
				if(empty($PostUserInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
        break;
    case 'UserName':
				if(empty($PostUserInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
      	/*
      	$UserInfo = GetUserInfoByUserName($PostUserInfo[$Key]);
      	if($UserInfo)
      	{
      		if($UserInfo['UserID'] != $PostUserInfo['UserID'])
      		{
      			$ActionMsg['FailedMsg'][] = $_LANG['UserNameExist'];
      		}
      	}*/
				break;
		case 'RealName':
				if(empty($PostUserInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
      	/*$UserInfo = GetUserInfoByRealName($PostUserInfo[$Key]);
      	if($UserInfo)
      	{
      		if($UserInfo['UserID'] != $PostUserInfo['UserID'])
      		{
      			$ActionMsg['FailedMsg'][] = $_LANG['RealNameExist'];
      		}
      	}*/
				break;
    case 'Email':
    		if(empty($PostUserInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
				elseif(!preg_match("/^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4}$/i", $PostUserInfo['Email']))
    		{
        		$ActionMsg['FailedMsg'][] = $_LANG['InvalidEmail'];
    		}
      	break;
  	}	
}

function ValidatePostOpenUserInfo($PostUserInfo,&$ActionMsg)
{		
		global $_LANG;
	  
	  foreach($_LANG['UserFields'] as $Key => $Value)
	  {
	  	ValidateUserInfoFieldValue($PostUserInfo,$Key,$ActionMsg);
    }
}

function ValidatePostEditUserInfo($PostUserInfo,$RawUserInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostUserInfo as $Key => $Value)
    {
        if($_LANG['UserFields'][$Key])
        {
        		ValidateUserInfoFieldValue($PostUserInfo,$Key,$ActionMsg);
        }
    }
}

function BuildSqlUserInsertArray($FieldList,$UserInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'UserID')
			{
					continue;
			}
					
			if(isset($UserInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $UserInfo[$Key];
			}
	}
}

function InsertUserInfo($PostUserInfo)
{   
		global $_LANG;
		
		/* Build UserInfo */
		//Get Original PostUserInfo
		$UserInfo = $PostUserInfo;
		
		//Get CurretnUser and CurrentDate
    $CurrentUser = $PostUserInfo['TestUserName'];
    $CurrentDate = date('Y-m-d H:i:s');
    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $UserInfo['AddedBy'] = $CurrentUser;	
   	$UserInfo['AddDate'] = $CurrentDate;
    $UserInfo['LastEditedBy'] = $CurrentUser;
   	$UserInfo['LastDate'] = $CurrentDate;
 
 		//Create the SqlInsertArray
		$SqlInsertArray = array();
		BuildSqlUserInsertArray($_LANG['UserFields'],$UserInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$UserID = dbInsertFieldRow('TestUser',$SqlInsertArray);
		
		return $UserID;
}

function BuildMailContentForOpenUser($PostInfo,$FieldList)
{    
		$MailContent = '';
		
		foreach($FieldList as $Key => $Value)
		{     
				if($PostInfo[$Key])
				{
        			$NewValue = $PostInfo[$Key];
        			if($Key == 'UserPassword')
        			{
        				$NewValue = $PostInfo['PlainUserPassword'];
    	  			}
    	  			$NewValue = sysAddSlash($NewValue);
        			$KeyName = $Value;
          		$MailContent .= "[b]{$KeyName}:[/b]  \"{$NewValue}\"\n";
        }
    }
    return $MailContent;
}

function SendOpenUserNotifyMail($PostUserInfo,$UserID)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('User',$PostUserInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('User',$PostUserInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build UserMailTitle
    $UserMailTitle = '['.$_LANG['TracSystem'].']'.' User ['.$PostUserInfo['UserName'].'] was Created';
    
    //Build MainMessage
 		$ActionUser = $_SESSION['TestUserName'];
 		$AssignedTo = $PostUserInfo['UserName'];
 		$MailContent = BuildMailContentForOpenUser($PostUserInfo,$_LANG['UserFields']);
		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($UserID,'Created',$ActionUser,$AssignedTo,$MailContent,'User');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $UserMailTitle, $MainMessage);
}

function GetUserInfoByUserName($UserName)
{
	global $_CFG;
	$WhereStr  = "UserName = '{$UserName}'";
	$UserInfo = dbGetRow($_CFG['UserTable']['TableName'], '', $WhereStr);
	return $UserInfo;
}

function GetUserInfoByRealName($RealName)
{
	global $_CFG;
	$WhereStr  = "RealName = '{$RealName}'";
	$UserInfo = dbGetRow($_CFG['UserTable']['TableName'], '', $WhereStr);
	return $UserInfo;
}
/**
 * Open User
 *
 * @author RainyGao <zju_rain@163.com>
 * @param  array  $PostUserInfo
 * @return array  $ActionMsg
 */
function testOpenUser($PostUserInfo)
{
    //Pre-Handler for PostUserInfo
		PostUserInfoPreHandler($PostUserInfo);

    /***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('User');
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenUserInfo($PostUserInfo,$ActionMsg);

    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostUserInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$UserID = InsertUserInfo($PostUserInfo);
		
		//SendOpenUserNotifyMail
		SendOpenUserNotifyMail($PostUserInfo,$UserID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['UserID'] = $UserID;
    return $ActionMsg;
}

/*=== Local APIs for User Edit Actions ======*/
function GetRawUserInfo($UserID)
{
		$Columns = '*';
  	$RawUserInfo = dbGetRow('TestUser',$Columns,"UserID = '{$UserID}'");	
  	return $RawUserInfo;
}

function GetUserDiffInfo($PostUserInfo,$RawUserInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostUserInfo = sysStripSlash($PostUserInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['UserFields']);
		$UserDiffInfo = array();
    $UserDiffInfo += sysArrayDiffAssoc($TempPostUserInfo, $RawUserInfo, $DiffAssoc);
		
		//UserID should never be changed as UserDiffInfo
    if($UserDiffInfo['UserID'])
    {
    		unset($UserDiffInfo['UserID']);
    }
    
    return $UserDiffInfo;
}

function IsUserInfoChanged($UserDiffInfo)
{
		if(!empty($UserDiffInfo))
		{
			return true;
		}
		return false;
}

function BuildSqlUserSetArray($FieldList,$UserInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//UserID should not be Changed
			if($Key == 'UserID')
			{
					continue;
			}
			
			if(isset($UserInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $UserInfo[$Key];
			}
	}		
}

function EditUserInfo($UserID,$PostUserInfo,$RawUserInfo,$UserDiffInfo)
{
		global $_LANG;
		
		/* Build UserInfo */
		//Get Original UserDiffInfo
		$UserInfo = $UserDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostUserInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
    
		//There is nothing to Update
    if(empty($UserInfo))
    {
    	 Rainy_Debug("No Fields in UserInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $UserInfo['LastEditedBy'] = $CurrentUser;
    $UserInfo['LastDate'] = $CurrentDate;

		//Build SqlSetList, It will filter out which is out of defined UserFields
		$SqlSetArray = array();
		BuildSqlUserSetArray($_LANG['UserFields'],$UserInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the UserInfo
    dbUpdateFieldRow('TestUser', $SqlSetArray, "UserID='{$UserID}'");
}

function BuildMailContentForEditUser($PostInfo,$RawInfo,$DiffInfo,$FieldList)
{    
		$MailContent = '';
		
		foreach($FieldList as $Key => $Value)
		{    
				if($DiffInfo[$Key])
				{
		        	$OldValue = FieldValueConvert($Key,$RawInfo[$Key]);
	  		    	$NewValue = FieldValueConvert($Key,$PostInfo[$Key]);
	      			if($Key == 'UserPassword')
        			{
        				$OldValue = '';
        				$NewValue = $PostInfo['PlainUserPassword'];
    	  			}
	      			$OldValue = sysAddSlash($OldValue);
    	  			$NewValue = sysAddSlash($NewValue);
        			$KeyName = $Value;
          		$MailContent .= "Changed [b]{$KeyName}[/b] from [b]\"{$OldValue}\"[/b] to[b]\"{$NewValue}\"[/b]\n";
        }
    }
    return $MailContent;
}

function SendEditUserNotifyMail($UserID,$PostUserInfo,$RawUserInfo,$UserDiffInfo)
{
		global $_LANG;

 		Rainy_Debug($PostUserInfo,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($RawUserInfo,__FUNCTION__,__LINE__,__FILE__);
		Rainy_Debug($UserDiffInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('User',$PostUserInfo,$RawUserInfo,$UserDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('User',$PostUserInfo,$RawUserInfo,$UserDiffInfo);
 		Rainy_Debug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
    //Build UserMailTitle
    $UserMailTitle = '['.$_LANG['TracSystem'].']'.' User ['.$PostUserInfo['UserName'].'] was Updated';
    Rainy_Debug($UserMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Build MainMessage
 		$ActionUser = $_SESSION['TestUserName'];
 		$AssignedTo = $PostUserInfo['UserName'];
    $MailContent = BuildMailContentForEditUser($PostUserInfo,$RawUserInfo,$UserDiffInfo,$_LANG['UserFields']);
    $MainMessage = testCreateMailMessage($UserID,'Updated',$ActionUser,$AssignedTo,$MailContent,'User');
    Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $UserMailTitle, $MainMessage);
}

/**
 * Edit User
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostUserInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditUser2($PostUserInfo)
{
    global $_LANG;
    
    Rainy_Debug("testEditUser2() Start",__FUNCTION__,__LINE__,__FILE__);
    
    //Get UserID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $UserID = $PostUserInfo['UserID'];
    
   	//Pre-Handler for PostUserInfo
		PostUserInfoPreHandler($PostUserInfo);
    //Rainy_Debug($PostUserInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('User',$UserID);
		
		//Get RawUserInfo
    $RawUserInfo = GetRawUserInfo($UserID);
		//Rainy_Debug($PostUserInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Validate PostUserInfo
		ValidatePostEditUserInfo($PostUserInfo,$RawUserInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostUserInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }
	  
		//GetUserDiffInfo
		$UserDiffInfo = GetUserDiffInfo($PostUserInfo,$RawUserInfo);
		//Rainy_Debug($UserDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update UserInfo
		EditUserInfo($UserID,$PostUserInfo,$RawUserInfo,$UserDiffInfo);

		//Check if UserInfo was changed
    if(IsUserInfoChanged($UserDiffInfo) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }
    
		//Send Notify Email
		SendEditUserNotifyMail($UserID,$PostUserInfo,$RawUserInfo,$UserDiffInfo);
		
		$ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

/*=== Local APIs for Project Open Actions ======*/
function PostProjectInfoPreHandler(&$PostProjectInfo)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostProjectInfo as $Key => $Value)
    {
        if($_LANG['ProjectFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'ProjectName':
               	case 'RealName':
                	$PostProjectInfo[$Key] = htmlspecialchars(trim($PostProjectInfo[$Key]));
                	break;
               	case 'NotifyEmail':
                	$PostProjectInfo[$Key] = trim($PostProjectInfo[$Key]);
                	break;
								case 'ProjectManagers':
                	$PostProjectInfo[$Key] = mysql_real_escape_string($PostProjectInfo[$Key]);
                	break;
            }
        }
    }
}

function ValidateProjectInfoFieldValue($PostProjectInfo,$Key,&$ActionMsg)
{
		global $_LANG;
		switch($Key)
  	{
  	case 'ProjectName':
		case 'ProjectManagers':
		//case 'ProjectGroupIDs':
		//case 'ProjectDoc':
		//case 'ProjectPlan':
		//case 'DisplayOrder':
		case 'NotifyEmail':
				if(empty($PostProjectInfo[$Key]))
  	    {
    	  	$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
      	}
        break;
  	}	
}

function ValidatePostOpenProjectInfo($PostProjectInfo,&$ActionMsg)
{		
		global $_LANG;
	  
	  foreach($_LANG['ProjectFields'] as $Key => $Value)
	  {
	  	ValidateProjectInfoFieldValue($PostProjectInfo,$Key,$ActionMsg);
    }
}

function ValidatePostEditProjectInfo($PostProjectInfo,$RawProjectInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostProjectInfo as $Key => $Value)
    {
        if($_LANG['ProjectFields'][$Key])
        {
        		ValidateProjectInfoFieldValue($PostProjectInfo,$Key,$ActionMsg);
        }
    }
}

function BuildSqlProjectInsertArray($FieldList,$ProjectInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//BugID should not be Changed
			if($Key == 'ProjectID')
			{
					continue;
			}
					
			if(isset($ProjectInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $ProjectInfo[$Key];
			}
	}
}

function InsertProjectInfo($PostProjectInfo)
{   
		global $_LANG;
		
		/* Build ProjectInfo */
		//Get Original PostProjectInfo
		$ProjectInfo = $PostProjectInfo;
		
		//Get CurretnProject and CurrentDate
    $CurrentUser = $PostProjectInfo['TestUserName'];
    $CurrentDate = date('Y-m-d H:i:s');
    
    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $ProjectInfo['AddedBy'] = $CurrentUser;	
   	$ProjectInfo['AddDate'] = $CurrentDate;
    $ProjectInfo['LastEditedBy'] = $CurrentUser;
   	$ProjectInfo['LastDate'] = $CurrentDate;
 
 		//Create the SqlInsertArray
		$SqlInsertArray = array();
		BuildSqlProjectInsertArray($_LANG['ProjectFields'],$ProjectInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$ProjectID = dbInsertFieldRow('TestProject',$SqlInsertArray);
		
		return $ProjectID;
}

/**
 * Open Project
 *
 * @author RainyGao <zju_rain@163.com>
 * @param  array  $PostProjectInfo
 * @return array  $ActionMsg
 */
function testOpenProject($PostProjectInfo)
{
    //Pre-Handler for PostProjectInfo
		PostProjectInfoPreHandler($PostProjectInfo);

    /***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Project');
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenProjectInfo($PostProjectInfo,$ActionMsg);

    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostProjectInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$ProjectID = InsertProjectInfo($PostProjectInfo);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['ProjectID'] = $ProjectID;
    return $ActionMsg;
}

/*=== Local APIs for Project Edit Actions ======*/
function GetRawProjectInfo($ProjectID)
{
		$Columns = '*';
  	$RawProjectInfo = dbGetRow('TestProject',$Columns,"ProjectID = '{$ProjectID}'");	
  	return $RawProjectInfo;
}

function GetProjectDiffInfo($PostProjectInfo,$RawProjectInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostProjectInfo = sysStripSlash($PostProjectInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['ProjectFields']);
		$ProjectDiffInfo = array();
    $ProjectDiffInfo += sysArrayDiffAssoc($TempPostProjectInfo, $RawProjectInfo, $DiffAssoc);
		
		//ProjectID should never be changed as ProjectDiffInfo
    if($ProjectDiffInfo['ProjectID'])
    {
    		unset($ProjectDiffInfo['ProjectID']);
    }
    
    return $ProjectDiffInfo;
}

function IsProjectInfoChanged($ProjectDiffInfo)
{
		if(!empty($ProjectDiffInfo))
		{
			return true;
		}
		return false;
}

function BuildSqlProjectSetArray($FieldList,$ProjectInfo,&$SetSqlArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//ProjectID should not be Changed
			if($Key == 'ProjectID')
			{
					continue;
			}
			
			if(isset($ProjectInfo[$Key]))	//如果传入的域存在
			{
				$SetSqlArray[$Key] = $ProjectInfo[$Key];
			}
	}		
}

function EditProjectInfo($ProjectID,$PostProjectInfo,$RawProjectInfo,$ProjectDiffInfo)
{
		global $_LANG;
		
		/* Build ProjectInfo */
		//Get Original ProjectDiffInfo
		$ProjectInfo = $ProjectDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostProjectInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
    
		//There is nothing to Update
    if(empty($ProjectInfo))
    {
    	 Rainy_Debug("No Fields in ProjectInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $ProjectInfo['LastEditedBy'] = $CurrentUser;
    $ProjectInfo['LastDate'] = $CurrentDate;

		//Build SqlSetList, It will filter out which is out of defined ProjectFields
		$SqlSetArray = array();
		BuildSqlProjectSetArray($_LANG['ProjectFields'],$ProjectInfo,$SqlSetArray);
		Rainy_Debug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the ProjectInfo
    dbUpdateFieldRow('TestProject', $SqlSetArray, "ProjectID='{$ProjectID}'");
}

/**
 * Edit Project
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostProjectInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditProject2($PostProjectInfo)
{
    global $_LANG;
    
    //Get ProjectID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostProjectInfo['ProjectID'];
    
   	//Pre-Handler for PostProjectInfo
		PostProjectInfoPreHandler($PostProjectInfo);
    //Rainy_Debug($PostProjectInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Project',$ProjectID);
		
		//Get RawProjectInfo
    $RawProjectInfo = GetRawProjectInfo($ProjectID);
		//Rainy_Debug($PostProjectInfo,__FUNCTION__,__LINE__,__FILE__);
		
		//Validate PostProjectInfo
		ValidatePostEditProjectInfo($PostProjectInfo,$RawProjectInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_Debug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_Debug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_Debug($PostProjectInfo,__FUNCTION__,__LINE__,__FILE__,0);	
        return $ActionMsg;
    }
	  
		//GetProjectDiffInfo
		$ProjectDiffInfo = GetProjectDiffInfo($PostProjectInfo,$RawProjectInfo);
		//Rainy_Debug($ProjectDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update ProjectInfo
		EditProjectInfo($ProjectID,$PostProjectInfo,$RawProjectInfo,$ProjectDiffInfo);

		//Check if ProjectInfo was changed
    if(IsProjectInfoChanged($ProjectDiffInfo) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }
    
		$ActionMsg['Bingle'] = true;
    return $ActionMsg;
}


/**
 * Edit user
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostUserInfo
 * @return array  $ActionMsg
 */
function testEditUser($PostUserInfo)
{
    global $_LANG, $_CFG;
		
		Rainy_Debug("testEditUser() Start",__FUNCTION__,__LINE__,__FILE__);

    $ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array());

    $PostUserInfo['UserName'] = htmlspecialchars(trim($PostUserInfo['UserName']));
    $PostUserInfo['RealName'] = htmlspecialchars(trim($PostUserInfo['RealName']));
    $PostUserInfo['Email'] = trim($PostUserInfo['Email']);

    $RawUserInfo = array_pop(dbGetList($_CFG['UserTable']['TableName'], $Columns, "UserName = '{$PostUserInfo[UserName]}'"));

    if(empty($PostUserInfo['RealName']))
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoRealName'];
    }
    if(empty($PostUserInfo['Email']) && isset($PostUserInfo['ReceiveEmail']))
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoEmail'];
    }
    elseif(!preg_match("/^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4}$/i", $PostUserInfo['Email']) && isset($PostUserInfo['ReceiveEmail']))
    {
        $ActionMsg['FailedMsg'][] = $_LANG['InvalidEmail'];
    }
    if($PostUserInfo['RawUserPassword'] != '')
    {
        if(baseEncryptUserPWD($PostUserInfo['RawUserPassword']) != $RawUserInfo['UserPassword'])
        {
            $ActionMsg['FailedMsg'][] = $_LANG['WrongRawUserPassword'];
        }
    }
    if($PostUserInfo['UserPassword'] != $PostUserInfo['RepeatUserPassword'])
    {
        $ActionMsg['FailedMsg'][] = $_LANG['PasswordNotEqual'];
    }

    if(!empty($ActionMsg['FailedMsg']))
    {
        return $ActionMsg;
    }

    $PostUserInfo['NoticeFlag'] = 0;

    if(isset($PostUserInfo['ReceiveEmail']))
    {
        $PostUserInfo['NoticeFlag'] += 2;
        unset($PostUserInfo['ReceiveEmail']);
    }

    if($PostUserInfo['UserPassword'] == '')
    {
        dbUpdateRow($_CFG['UserTable']['TableName'], 'RealName', "'{$PostUserInfo[RealName]}'"
                                                   , 'Email', "'{$PostUserInfo[Email]}'"
                                                   , 'NoticeFlag', "'{$PostUserInfo[NoticeFlag]}'"
                                                   , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                                                   , 'LastDate', 'now()'
                                                   , "UserName = '{$PostUserInfo[UserName]}'");
    }
    else
    {
        $PostUserInfo['UserPassword'] = baseEncryptUserPWD($PostUserInfo['UserPassword']);
        dbUpdateRow($_CFG['UserTable']['TableName'], 'RealName', "'{$PostUserInfo[RealName]}'"
                                                   , 'UserPassword', "'{$PostUserInfo[UserPassword]}'"
                                                   , 'Email', "'{$PostUserInfo[Email]}'"
                                                   , 'NoticeFlag', "'{$PostUserInfo[NoticeFlag]}'"
                                                   , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                                                   , 'LastDate', 'now()'
                                                   , "UserName = '{$PostUserInfo[UserName]}'");
    }

    $_SESSION['TestRealName'] = $PostUserInfo['RealName'];
    $ActionMsg['Bingle'] = true;

    return $ActionMsg;

}

/**
 * Open Result
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostResultInfo
 * @return array  $ActionMsg
 */
function testOpenResult($PostResultInfo)
{
    global $_LANG;

    $ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ResultID'=>'0');

    $ProjectID = $PostResultInfo['ProjectID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$PostResultInfo[ProjectID]}'");
    $ProjectName = $ProjectInfo['ProjectName'];
    $ModulePath = testGetModulePath($PostResultInfo['ModuleID']);
    $OpenedBy = $PostResultInfo['TestUserName'];
    $LastEditedBy = $OpenedBy;
    $MailToList = testGetMailToList(sysStripSlash($PostResultInfo['MailTo']), $ProjectID);
    $PostResultInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
    $PostResultInfo['ResultKeyword'] = htmlspecialchars(trim($PostResultInfo['ResultKeyword']));
    $PostResultInfo['ResultBuild'] = htmlspecialchars(trim($PostResultInfo['ResultBuild']));
    $PostResultInfo['ResultMachine'] = htmlspecialchars(trim($PostResultInfo['ResultMachine']));
    $PostResultInfo['ResultSteps'] = htmlspecialchars($PostResultInfo['ResultSteps']);
    $PostResultInfo['ReplyNote'] = htmlspecialchars(trim($PostResultInfo['ReplyNote']));
    $PostResultInfo['ResultTitle'] = htmlspecialchars(trim($PostResultInfo['ResultTitle']));

    if($PostResultInfo['ResultValue'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultValue'];
    }
    if($PostResultInfo['ResultBuild'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultBuild'];
    }
    if($PostResultInfo['ResultSteps'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultSteps'];
    }

    if(!empty($ActionMsg['FailedMsg']))
    {
        return $ActionMsg;
    }


    if($PostResultInfo[AssignedTo] != '')
    {
        $AssignDate = 'now()';
    }
    else
    {
        $AssignDate = "''";
    }


    $ValueSql .= "'{$ProjectID}','{$ProjectName}','{$PostResultInfo[ModuleID]}','{$ModulePath}','{$PostResultInfo[CaseID]}','{$PostResultInfo[ResultTitle]}','{$PostResultInfo[ResultValue]}','{$PostResultInfo[ResultStatus]}',";
    $ValueSql .= "'{$PostResultInfo[ResultOS]}','{$PostResultInfo[ResultBrowser]}','{$PostResultInfo[ResultMachine]}','{$PostResultInfo[ResultKeyword]}','{$PostResultInfo[MailTo]}','{$PostResultInfo[ResultSteps]}',";
    $ValueSql .= "'{$OpenedBy}',now(),'{$PostResultInfo[ResultBuild]}','{$PostResultInfo[AssignedTo]}',{$AssignDate},'{$LastEditedBy}',now(),',{$OpenedBy},'";

    // insert Result
    $ResultID = dbInsertRow('ResultInfo',$ValueSql,"ProjectID,ProjectName,ModuleID,ModulePath,CaseID,ResultTitle,ResultValue,ResultStatus,
                                                    ResultOS,ResultBrowser,ResultMachine,ResultKeyword,MailTo,ResultSteps,
                                                    OpenedBy,OpenedDate,ResultBuild,AssignedTo,AssignedDate,LastEditedBy,LastEditedDate,ModifiedBy");

    $ActionID = testAddAction('Result',$ResultID,$OpenedBy,'Opened','',$PostResultInfo['ReplyNote']);



     // update Caseinfo
    dbUpdateRow('CaseInfo','LastEditedBy',"'{$OpenedBy}'",'LastEditedDate','now()',
                           'ModifiedBy', "CONCAT(ModifiedBy,'{$OpenedBy}',',')",
                           "CaseID='{$PostResultInfo[CaseID]}'");

    $EditCaseActionID = testAddAction('Case',$PostResultInfo[CaseID], $OpenedBy,'Run','',"Test Result #[result]{$ResultID}[/result]");


    $EditedCase = dbGetRow('CaseInfo','ResultID',"CaseID='{$PostResultInfo[CaseID]}'");

    testAddHistory($EditCaseActionID, 'ResultID', $EditedCase['ResultID'], $EditedCase['ResultID'].$ResultID.',');


    if($PostResultInfo[CaseID]> 0)
    {
        dbUpdateRow('CaseInfo','ResultID',"CONCAT(ResultID,'{$ResultID}',',')", "CaseID={$PostResultInfo[CaseID]}");
    }

    $AssignedToUserInfo = testGetUserInfoByName($PostResultInfo['AssignedTo']);
    if($PostResultInfo['AssignedTo'] != $PostResultInfo['TestUserName'])
    {
        $AssignedToMail = $AssignedToUserInfo['Email'];
        $AssignedToUserInfo['RealName'] == '' ? $AssignedToUserInfo['RealName'] = $PostResultInfo['AssignedTo'] : '';
    }
    if(($AssignedToUserInfo['NoticeFlag'] & 2) != 2)
    {
        $AssignedToMail = '';
    }
    $MailToList = testGetMailToList(sysStripSlash($PostResultInfo['MailTo']), $ProjectID, true);
    $MainMessage = testCreateMailMessage($ResultID,'Opened',$PostResultInfo['TestRealName'],$AssignedToUserInfo['RealName'], $PostResultInfo['ReplyNote'] . "\n" . str_repeat("-", 20) . "\n" . $PostResultInfo['ResultSteps'],'Result');
    sysMail($AssignedToMail, $MailToList['Email'], 'Result #' . $ResultID . ' ' . $PostResultInfo['ResultTitle'], $MainMessage);

    $ActionMsg['Bingle'] = true;
    $ActionMsg['ResultID'] = $ResultID;
    $ActionMsg['ActionID'] = $ActionID;

    return $ActionMsg;

}

/**
 * Edit Result
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostResultInfo
 * @param  bool   $UploadFile  Upload file or not
 * @return array  $ActionMsg
 */
function testEditResult($PostResultInfo,$UploadFile = false)
{
    global $_LANG;

    $ActionMsg = array('Bingle'=>false,'BingleMsg'=>array(), 'FailedMsg'=>array(), 'ResultID'=>'0');

    $ResultID = $PostResultInfo['ResultID'];
    $ProjectID = $PostResultInfo['ProjectID'];
    $LastEditedBy = $PostResultInfo['TestUserName'];
    $MailToList = testGetMailToList(sysStripSlash($PostResultInfo['MailTo']), $ProjectID);
    $PostResultInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
    $PostResultInfo['ResultBuild'] = htmlspecialchars(trim($PostResultInfo['ResultBuild']));
    $PostResultInfo['ResultMachine'] = htmlspecialchars(trim($PostResultInfo['ResultMachine']));
    $PostResultInfo['ResultSteps'] = htmlspecialchars($PostResultInfo['ResultSteps']);
    $PostResultInfo['ReplyNote'] = htmlspecialchars(trim($PostResultInfo['ReplyNote']));
    $PostResultInfo['ResultKeyword'] = htmlspecialchars(trim($PostResultInfo['ResultKeyword']));

    if($PostResultInfo['ResultValue'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultValue'];
    }
    if($PostResultInfo['ResultBuild'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultBuild'];
    }
    if($PostResultInfo['ResultSteps'] == '')
    {
        $ActionMsg['FailedMsg'][] = $_LANG['NoResultSteps'];
    }

    if(!empty($ActionMsg['FailedMsg']))
    {
        return $ActionMsg;
    }

    if($PostResultInfo[AssignedTo] != '')
    {
        $AssignDate = 'now()';
    }
    else
    {
        $AssignDate = "''";
    }

    $Columns = '*';
    $RawResultInfo = dbGetRow('ResultInfo',$Columns,"ResultID = '{$PostResultInfo[ResultID]}'");
    $TempPostResultInfo = sysStripSlash($PostResultInfo);

    $ResultDiffInfo = array();
    $DiffAssoc = 'ResultValue,ResultStatus,MailTo,ResultSteps,AssignedTo,ResultOS,ResultBrowser,ResultMachine,ResultBuild,ResultKeyword';
    $ResultDiffInfo += sysArrayDiffAssoc($TempPostResultInfo, $RawResultInfo, $DiffAssoc);

    if(isset($ResultDiffInfo['AssignedTo']))
    {
        $EditPostArray['AssignedDate'] = date('Y-m-d H:i:s');
        $PostResultInfo['AssignedDate'] = $EditPostArray['AssignedDate'];
    }
    else
    {
        $PostResultInfo['AssignedDate'] = $RawResultInfo['AssignedDate'];
    }

    if(stripslashes(($PostResultInfo['ResultSteps'])) != $RawResultInfo['ResultSteps'])
    {
        $ResultDiffInfo['ResultSteps'] = stripslashes($PostResultInfo['ResultSteps']);
    }

    $EditPostArray = array();
    $EditPostArray += $ResultDiffInfo;
    if($PostResultInfo['ReplyNote'] != '' || $UploadFile)
    {
        $EditPostArray['ReplyNote'] = htmlspecialchars(trim($PostResultInfo['ReplyNote']));
    }

    // check Result step
    if(empty($EditPostArray))
    {
        $ActionMsg['Bingle'] = true;
        $ActionMsg['ResultID'] = $ResultID;
        return $ActionMsg;
    }
    else
    {
        $LastActionID = testGetLastActionID('Result',$ResultID);
        if($PostResultInfo['LastActionID'] != $LastActionID)
        {
            $ActionMsg['FailedMsg'][] = $_LANG['ResultAlreadyChanged'];
            return $ActionMsg;
        }
    }

    // update Resultinfo
    dbUpdateRow('ResultInfo','ResultValue',"'{$PostResultInfo[ResultValue]}'",
                             'ResultStatus',"'{$PostResultInfo[ResultStatus]}'",
                             'MailTo',"'{$PostResultInfo[MailTo]}'",
                             'ResultSteps',"'{$PostResultInfo[ResultSteps]}'",
                             'AssignedTo',"'{$PostResultInfo[AssignedTo]}'",
                             'AssignedDate', "'{$PostResultInfo[AssignedDate]}'",
                             'ResultOS', "'{$PostResultInfo[ResultOS]}'",
                             'ResultBrowser', "'{$PostResultInfo[ResultBrowser]}'",
                             'ResultMachine',"'{$PostResultInfo[ResultMachine]}'",
                             'ResultBuild',"'{$PostResultInfo[ResultBuild]}'",
                             'ResultKeyword',"'{$PostResultInfo[ResultKeyword]}'",
                             'LastEditedBy',"'{$LastEditedBy}'",'LastEditedDate','now()',
                             'ModifiedBy', "CONCAT(ModifiedBy,'{$LastEditedBy}',',')",
                             "ResultID='{$ResultID}'");

    // insert action
    $ActionID = testAddAction('Result',$ResultID,$LastEditedBy,'Edited','',$EditPostArray['ReplyNote']);

    // insert histroy
    $ChangeNote = '';
    foreach($ResultDiffInfo as $Key => $Value)
    {
        $OldValue = htmlspecialchars($RawResultInfo[$Key]);
        $NewValue = htmlspecialchars($ResultDiffInfo[$Key]);
        testAddHistory($ActionID, $Key, $OldValue, $NewValue);
        $OldValue = sysAddSlash($OldValue);
        $NewValue = sysAddSlash($NewValue);

        if($Key == 'ResultSteps')
        {
            $OldValue = '...';
            $NewValue = '...';
        }
        if(array_key_exists($Key, $_LANG['ResultFields']))
        {
            $Key = $_LANG['ResultFields']["$Key"];
        }
        $ChangeNote .= "Changed [b]{$Key}[/b] from [b]\"{$OldValue}\"[/b] to[b]\"{$NewValue}\"[/b]\n";
    }

    $AssignedToUserInfo = testGetUserInfoByName($PostResultInfo['AssignedTo']);
    if($PostResultInfo['AssignedTo'] != $PostResultInfo['TestUserName'])
    {
        $AssignedToMail = $AssignedToUserInfo['Email'];
        $AssignedToUserInfo['RealName'] == '' ? $AssignedToUserInfo['RealName'] = $PostResultInfo['AssignedTo'] : '';
    }
    if(($AssignedToUserInfo['NoticeFlag'] & 2) != 2)
    {
        $AssignedToMail = '';
    }
    $MainMessage = testCreateMailMessage($ResultID,$ActionType,$PostResultInfo['TestRealName'],$AssignedToUserInfo['RealName'], $ChangeNote ."\n". $PostResultInfo['ReplyNote'],'Result', $ActionNote);
    $MailToList = testGetMailToList(sysStripSlash($PostResultInfo['MailTo']), $ProjectID, true);
    sysMail($AssignedToMail, $MailToList['Email'], 'Result #' . $ResultID . ' ' . $PostResultInfo['ResultTitle'], $MainMessage);

    $ActionMsg['Bingle'] = true;
    $ActionMsg['ResultID'] = $ResultID;
    $ActionMsg['ActionID'] = $ActionID;

    return $ActionMsg;
}

/*=== Local APIs for Case Open Actions ======*/
function PostCaseInfoPreHandler(&$PostCaseInfo,$ProjectID,$ProjectInfo,$ModulePath)
{
		global $_LANG;
		
		/* Do String Convert */    
    foreach($PostCaseInfo as $Key => $Value)
    {
        if($_LANG['CaseFields'][$Key])
        {
            // for call eval function
            switch($Key)
            {
                case 'CaseTitle':
                	$PostCaseInfo[$Key] = sysDbSubStr(htmlspecialchars($PostCaseInfo['CaseTitle']), 150);
                	break;
         				
								case 'CaseDescription':
								case 'CaseSetup':
                case 'CaseSteps':
                case 'CaseCriteria':
 									//textfield format data convert
                	$PostCaseInfo[$Key] = htmlspecialchars($PostCaseInfo[$Key]);
                	break;

								case 'DisplayOrder':
									if($PostCaseInfo['DisplayOrder'] == '')
    							{
        						$PostCaseInfo['DisplayOrder'] = 0;
    							}
							    else if(!preg_match("/^[0-9]*$/i", $PostCaseInfo['DisplayOrder']))
							    {
							        $PostCaseInfo['DisplayOrder'] = 0;
							    }
							    else if(intval($PostCaseInfo['DisplayOrder'])>255 || intval($PostCaseInfo['DisplayOrder'])<0)
							    {
							        $PostCaseInfo['DisplayOrder'] = 0;
							    }
             			break;
             			
             			case 'ScriptedDate':
                		$PostCaseInfo[$Key] = trim($PostCaseInfo[$Key]);
                	break;   
                	                
                case 'MailTo':
                	$MailToList = testGetMailToList(sysStripSlash($PostCaseInfo['MailTo']), $ProjectID, true);
                	$PostCaseInfo['MailTo'] = mysql_real_escape_string($MailToList['MailToStr']);
                	break;
                
                case 'CaseKeyword':
									//input text format data convert
                	$PostCaseInfo[$Key] = htmlspecialchars(trim($PostCaseInfo[$Key]));
                	break;
                
                case 'LinkID':
                	$PostCaseInfo[$Key] = dbGetValidValueList($PostCaseInfo[$Key], 'CaseInfo','CaseID');
                	break;
                
                case 'BugID':
                	$PostCaseInfo[$Key] = dbGetValidValueList($PostCaseInfo[$Key], 'BugInfo','BugID');
							    if($PostCaseInfo['BugID']!='')
        					{
        						$PostCaseInfo['BugID'] = ',' . $PostCaseInfo['BugID'] . ',';
									}
                	break;
            }
        }
    }
    
    
    //Set ProjectName and ModulePath
    if(isset($PostCaseInfo['ProjectID']))
    {
    	$PostCaseInfo['ProjectName'] = $ProjectInfo['ProjectName'];
    }

    if(isset($PostCaseInfo['ModuleID']))
    {
    	$PostCaseInfo['ModulePath'] = $ModulePath;
		}
		
		if(!empty($PostCaseInfo['ReplyNote'])) 
		{   
    	$PostCaseInfo['ReplyNote'] = htmlspecialchars(trim($PostCaseInfo['ReplyNote']));
    }
    
}

function ValidateCaseInfoFieldValue($PostCaseInfo,$Key,&$ActionMsg)
{
		 global $_LANG;
		 switch($Key)
	   {
        		case 'ProjectID':
						case 'ProjectName':
						//case 'ModuleID':
						case 'ModulePath':
	  				case 'CaseIndex':
	  				case 'CaseTitle':
	  				case 'CaseType':
	  				case 'CaseDescription':
	  				case 'CaseSteps':
	  				case 'CaseCriteria':
	  				case 'CasePriority':
	  				case 'CaseMethod':
	  					if($PostCaseInfo[$Key] == '')
    					{
        				$ActionMsg['FailedMsg'][] = $_LANG['EmptyErrorMsg'][$Key];
    					}
	  					break;
	  				case 'ScriptedDate':
    					if($PostCaseInfo['ScriptedDate'] != '' && !sysCheckDateFormat($PostCaseInfo['ScriptedDate']))
    					{
        					$ActionMsg['FailedMsg'][] = $_LANG['BadScriptedDate'];
    					}
        			break;
     }
}

function ValidatePostOpenCaseInfo($PostCaseInfo,&$ActionMsg)
{		
		global $_LANG;
	  foreach($_LANG['CaseFields'] as $Key => $Value)
	  {
	  		ValidateCaseInfoFieldValue($PostCaseInfo,$Key,$ActionMsg);
    }
}

function BuildSqlCaseInsertArray($FieldList,$CaseInfo,&$SqlInsertArray)
{
	foreach($FieldList as $Key => $Value)
	{
			//CaseID should not be Changed
			if($Key == 'CaseID')
			{
					continue;
			}
					
			if(isset($CaseInfo[$Key]))	//如果传入的域存在
			{
				$SqlInsertArray[$Key] = $CaseInfo[$Key];
			}
	}
}

function InsertCaseInfo($PostCaseInfo)
{
		global $_LANG;

    //Get CurrentUser and CurrentDate
		$CurrentUser = $PostCaseInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');

    //Set OpenedBy and LastEditedBy and ModifiedBy and Date
    $PostCaseInfo['OpenedBy'] = $CurrentUser;	
   	$PostCaseInfo['OpenedDate'] = $CurrentDate;
    $PostCaseInfo['LastEditedBy'] = $CurrentUser;
   	$PostCaseInfo['LastEditedDate'] = $CurrentDate;
    $PostCaseInfo['ModifiedBy'] = $CurrentUser;
		
		//Set AssignedDate
    if($PostCaseInfo['AssignedTo'] != '')
    {
        $AssignDate = $CurrentDate;
    }
    else
    {
        $AssignDate = '';
    }
 		$PostCaseInfo['AssignedDate'] = $AssignDate;		

 		//Set CasePriority
	  if($PostCaseInfo['CasePriority']===NULL)
	  {
	  		$PostCaseInfo['CasePriority'] = 'NULL';
	  }
	  
	  //Set CaseStatus
	  if($PostCaseInfo['CaseStatus']===NULL) 
	  {
	  		$PostCaseInfo['CaseStatus']='Active';
		}
									
		//Get Original PostCaseInfo
		$CaseInfo = $PostCaseInfo;
		//Create the ValueSqlString and KeySqlString
		$SqlInsertArray = array();
		BuildSqlCaseInsertArray($_LANG['CaseFields'],$CaseInfo,$SqlInsertArray);
		Rainy_Debug($SqlInsertArray,__FUNCTION__,__LINE__,__FILE__);

		$CaseID = dbInsertFieldRow('CaseInfo',$SqlInsertArray);
		
		return $CaseID;
}

function SendOpenCaseNotifyMail($PostCaseInfo,$CaseID,$ProjectID)
{
		global $_LANG;
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForOpenAction('Case',$PostCaseInfo);
 		$EmailCCList = GetEmailCCListForOpenAction('Case',$PostCaseInfo);
 		Rainy_DeBug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_Debug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
 		
 		//Build CaseMailTitle		
    $CaseMailTitle = '['.$_LANG['TracSystem'].']'.' Case'.$CaseID.' was raised: '.$PostCaseInfo['CaseTitle'];
    Rainy_Debug($CaseMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Build MainMessage
 		$ActionUser = $PostCaseInfo['TestUserName'];
 		$AssignedTo = $PostCaseInfo['AssignedTo'];
 		$MailContent = BuildMailContentForOpenAction($PostCaseInfo,$_LANG['CaseFields']);
 		Rainy_Debug($MailContent,__FUNCTION__,__LINE__,__FILE__);
    $MainMessage = testCreateMailMessage($CaseID,'Opened',$ActionUser,$AssignedTo,$MailContent,'Case');
    
    //Send the Email
    $EmailToListStr = join(',', $EmailToList);
    Rainy_Debug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $CaseMailTitle, $MainMessage);
}

/**
 * Open Case
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $PostCaseInfo
 * @return array  $ActionMsg
 */
function testOpenCase($PostCaseInfo)
{	   
    //Get ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostCaseInfo['ProjectID'];
    $ModuleID = $PostCaseInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);

   	//Pre-Handler for PostCaseInfo
		PostCaseInfoPreHandler($PostCaseInfo,$ProjectID,$ProjectInfo,$ModulePath);

		/***** Init ActionMsg ****/
    $ActionMsg = OpenActionMsgInit('Case');	
    
		/***** Validate PostInfo and CustomedFields ***/
		//Validate PostInfo
		ValidatePostOpenCaseInfo($PostCaseInfo,$ActionMsg);
 
    //Check Validation Result
    if(!empty($ActionMsg['FailedMsg']))
    {
    		Rainy_DeBug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_DeBug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_DeBug($PostCaseInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }

		/*** Add an Record in Database*/
		$CaseID = InsertCaseInfo($PostCaseInfo);
		$PostCaseInfo['CaseID'] = $CaseID;

    //Insert Post Action
    $ActionID = InsertAddAction($PostCaseInfo,'Case',$CaseID);

		//SendOpenCaseNotifyMail
		SendOpenCaseNotifyMail($PostCaseInfo,$CaseID,$ProjectID);
	
		//Set the Success ActionMsg
    $ActionMsg['Bingle'] = true;
    $ActionMsg['CaseID'] = $CaseID;
    $ActionMsg['ActionID'] = $ActionID;
    return $ActionMsg;
}

function GetRawCaseInfo($CaseID)
{
		$Columns = '*';
  	$RawCaseInfo = dbGetRow('CaseInfo',$Columns,"CaseID = '{$CaseID}'");	
  	return $RawCaseInfo;
}

function ValidatePostEditCaseInfo($PostCaseInfo,$RawCaseInfo,&$ActionMsg)
{
		global $_LANG;
    foreach($PostCaseInfo as $Key => $Value)
    {
        if($_LANG['CaseFields'][$Key])
       	{
						ValidateCaseInfoFieldValue($PostCaseInfo,$Key,$ActionMsg);
        }
    } 

    $LastActionID = testGetLastActionID('Case',$PostCaseInfo['CaseID']);
    if($PostCaseInfo['LastActionID'] != $LastActionID)
    {
         $ActionMsg['FailedMsg'][] = $_LANG['CaseAlreadyChanged'];
    }
}

function GetCaseDiffInfo($PostCaseInfo,$RawCaseInfo,$ProjectInfo,$ModulePath)
{
		global $_LANG;

		$TempPostCaseInfo = sysStripSlash($PostCaseInfo);
		$DiffAssoc = GetDiffAssocStr($_LANG['CaseFields']);
		$CaseDiffInfo = array();
    $CaseDiffInfo += sysArrayDiffAssoc($TempPostCaseInfo, $RawCaseInfo, $DiffAssoc);
		
		//CaseID should never be changed as CaseDiffInfo
    if($CaseDiffInfo['CaseID'])
    {
    		unset($CaseDiffInfo['CaseID']);
    }
    
    return $CaseDiffInfo;
}

function EditCaseInfo($CaseID,$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo)
{
		global $_LANG;
		
		/* Build CaseInfo */
		//Get Original CaseDiffInfo
		$CaseInfo = $CaseDiffInfo;
		
		//Get CurrentUser and CurrentDate
		$CurrentUser = $PostCaseInfo['TestUserName'];
		$CurrentDate = date('Y-m-d H:i:s');
    
		//There is nothing to Update
    if(empty($CaseInfo))
    {
    	 Rainy_Debug("No Field in CaseInfo was updated!!!",__FUNCTION__,__LINE__,__FILE__,1);
       return;
    }
		
		//Set LastEditedBy and Date
    $CaseInfo['LastEditedBy'] = $CurrentUser;
    $CaseInfo['LastEditedDate'] = $CurrentDate;

		//Set ModifiedBy
		$CaseInfo['ModifiedBy'] = "{$RawCaseInfo[ModifiedBy]},{$CaseInfo[LastEditedBy]}";
		
		//Build SqlSetList, It will filter out which is out of defined CaseFields
		$SqlSetArray = array();
		BuildSqlSetArray($_LANG['CaseFields'],$CaseInfo,$SqlSetArray);
		Rainy_DeBug($SqlSetArray,__FUNCTION__,__LINE__,__FILE__);
		
		//Update the CaseInfo
    dbUpdateFieldRow('CaseInfo', $SqlSetArray, "CaseID='{$CaseID}'");
}

function IsCaseInfoChanged($CaseDiffInfo,$PostCaseInfo,$UploadFile)
{
		if(!empty($CaseDiffInfo) || $PostCaseInfo['ReplyNote'] != '' || $UploadFile)
    {
			return true;
		}
		return false;
}

function SendEditCaseNotifyMail($CaseID,$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo,$UploadFile)
{
		global $_LANG;
		
		//Get Email To and CCList
 		$EmailToList = GetEmailToListForEditAction('Case',$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo);
 		$EmailCCList = GetEmailCCListForEditAction('Case',$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo);
 		Rainy_DeBug($EmailToList,__FUNCTION__,__LINE__,__FILE__);
 		Rainy_DeBug($EmailCCList,__FUNCTION__,__LINE__,__FILE__);
		
		//Set ActionType
    $ActionType = $PostCaseInfo['ActionType'];
    Rainy_DeBug($ActionType,__FUNCTION__,__LINE__,__FILE__);
    
    //Set CaseMailTitle    
    $MailPrefix = '['.$_LANG['TracSystem'].'] Case'.$CaseID.' was '.$ActionType.': ';
    $CaseMailTitle = $MailPrefix.$PostCaseInfo['CaseTitle'];
    Rainy_DeBug($CaseMailTitle,__FUNCTION__,__LINE__,__FILE__);
    
    //Set MainMessage
 		$ActionUser = $PostCaseInfo['TestUserName'];
 		$AssignedTo = $PostCaseInfo['AssignedTo'];
    $MailContent = BuildMailContentForEditAction($PostCaseInfo,$RawCaseInfo,$CaseDiffInfo,$_LANG['CaseFields']);
    $MainMessage = testCreateMailMessage($CaseID, $ActionType ,$ActionUser,$AssignedTo,$MailContent,'Case');
    Rainy_DeBug($MailContent,__FUNCTION__,__LINE__,__FILE__);
  	
  	//Send the email
  	$EmailToListStr = join(',', $EmailToList);
    Rainy_DeBug($EmailToListStr,__FUNCTION__,__LINE__,__FILE__);
    sysMail($EmailToListStr, $EmailCCList, $CaseMailTitle, $MainMessage);
}

/**
 * Edit Case
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param  array  $EditCaseInfo
 * @param  bool   $UploadFile   Upload file or not
 * @return array  $ActionMsg
 */
function testEditCase($PostCaseInfo, $UploadFile = false)
{
    global $_LANG;
    
    Rainy_DeBug($PostCaseInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Get CaseID and ProjectID and ModuleID, ProjectInfo and ModulePath
    $CaseID = $PostCaseInfo['CaseID'];
		
    //Get RawCaseInfo
    $RawCaseInfo = GetRawCaseInfo($CaseID);
		
		//ProjectID and ModuleID, ProjectInfo and ModulePath
    $ProjectID = $PostCaseInfo['ProjectID'];
    $ModuleID = $PostCaseInfo['ModuleID'];
    $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
    $ModulePath = testGetModulePath($ModuleID);
    
   	//Pre-Handler for PostCaseInfo
		PostCaseInfoPreHandler($PostCaseInfo,$ProjectID,$ProjectInfo,$ModulePath);
    //Rainy_DeBug($PostCaseInfo,__FUNCTION__,__LINE__,__FILE__);
    
    //Init ActionMsg		
    $ActionMsg = EditActionMsgInit('Case',$CaseID);
		
		//Validate PostCaseInfo
		ValidatePostEditCaseInfo($PostCaseInfo,$RawCaseInfo,$ActionMsg);
		
	  if(!empty($ActionMsg['FailedMsg']))
    {
    	  Rainy_DeBug("Validate Failed",__FUNCTION__,__LINE__,__FILE__,2);
    		Rainy_DeBug($ActionMsg[FailedMsg],__FUNCTION__,__LINE__,__FILE__,1);
	  		Rainy_DeBug($PostCaseInfo,__FUNCTION__,__LINE__,__FILE__,0);
        return $ActionMsg;
    }
	  
		//GetCaseDiffInfo
		$CaseDiffInfo = GetCaseDiffInfo($PostCaseInfo,$RawCaseInfo,$ProjectInfo,$ModulePath);
		Rainy_DeBug($CaseDiffInfo,__FUNCTION__,__LINE__,__FILE__);

		//Update CaseInfo
		EditCaseInfo($CaseID,$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo);

		//Check if CaseInfo was changed
    if(IsCaseInfoChanged($CaseDiffInfo,$PostCaseInfo,$UploadFile) == false)
    {
    		$ActionMsg['Bingle'] = true;
        return $ActionMsg;
    }

    //Insert Edit Action
    $ActionID = InsertEditAction($PostCaseInfo,'Case',$CaseID);

    //Add the Histroy Info to the EditAction
    InsertEditHistoryInfo($ActionID,$RawCaseInfo,$CaseDiffInfo);
    
		//Send Notify Email
		Rainy_DeBug($PostCaseInfo['SendNotifyEmail'],__FUNCTION__,__LINE__,__FILE__);
		if($PostCaseInfo['SendNotifyEmail'] == 'SendNotifyEmail')
		{
			SendEditCaseNotifyMail($CaseID,$PostCaseInfo,$RawCaseInfo,$CaseDiffInfo,$UploadFile);
		}
		
		$ActionMsg['ActionID'] = $ActionID;
		$ActionMsg['CaseID'] = $CaseID;
    $ActionMsg['Bingle'] = true;
    return $ActionMsg;
}

function GetObjIDPrefix($ObjType)
{
		global $_LANG;
		
		$ObjIDPrefix = '';
		switch($ObjType)
		{
		case 'Bug':
			$ObjIDPrefix = $_LANG['BugIDPrefix'];
			break;
		case 'Change':
			$ObjIDPrefix = $_LANG['ChangeIDPrefix'];
			break;
		case 'Review':
			$ObjIDPrefix = $_LANG['ReviewIDPrefix'];
			break;
		case 'ReviewComment':
			$ObjIDPrefix = $_LANG['ReviewCommentIDPrefix'];
			break;
		}
		return $ObjIDPrefix;
}

function GetLinkStr($ObjType,$ObjID)
{
		global $_CFG;
		
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'ReviewComment':
			$LinkStr = $_CFG['BaseURL'].'/'.$ObjType.'.php?'.$ObjType.'ID='.$ObjID;
			break;
		case 'Review':
			$LinkStr = $_CFG['BaseURL'].'/Review.php?'.$ObjType.'ID='.$ObjID;
			break;
		case 'User':
			$LinkStr = $_CFG['BaseURL'];
			//$LinkStr = "http://172.16.17.160/TracSystem";
			break;
		}
		return $LinkStr;		
}

function GetLinkName($ObjType,$ObjID)
{
		global $_CFG;
		
		switch($ObjType)
		{
		case 'Bug':
		case 'Change':
		case 'Review':
		case 'ReviewComment':
			$ObjIDPrefix = GetObjIDPrefix($ObjType);
			$LinkName = $ObjIDPrefix.$ObjID;
			break;
		case 'User':
			$LinkName = $_CFG['BaseURL'];
			//$LinkName = "http://172.16.17.160/TracSystem";
			break;
		}
		return $LinkName;
}

/**
 * Get mail template
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param   string  $IdList
 * @param   string  $Action
 * @param   string  $ActionUser
 * @param   string  $AssignedTo
 * @param   string  $Notes
 * @param   string  $ObjType   Bug,Case or Result
 */
function testCreateMailMessage($IdList, $Action, $ActionUser, $AssignedTo, $Notes, $ObjType, $ActionDesc = '')
{
    global $_CFG;
    global $TPL;

    if(empty($IdList))
    {
        return false;;
    }

    // Get css style.
    $CssStyle = join("",file($_CFG['RealRootPath'] . "/Css/Mail.css"));
    $TPL->assign("CssStyle",$CssStyle);

    // Bug Info.
    $ObjList = explode(',', $IdList);
    $TPL->assign("ObjList",$ObjList);
		Rainy_Debug($ObjList,__FUNCTION__,__LINE__,__FILE__);
				
		//Set the LinkName
		foreach($ObjList as $Index => $ObjID)
		{
			$Link[$ObjID] = GetLinkStr($ObjType,$ObjID);
			$LinkName[$ObjID] = GetLinkName($ObjType,$ObjID);
		}
		Rainy_Debug($Link,__FUNCTION__,__LINE__,__FILE__);
		Rainy_Debug($LinkName,__FUNCTION__,__LINE__,__FILE__);
		$TPL->assign("Link", $Link);
    $TPL->assign("LinkName", $LinkName);
    
    // Change info.
    $TPL->assign("ActionUser", $ActionUser);
    $TPL->assign("AssignedTo", $AssignedTo);
    $TPL->assign("ObjType", $ObjType);
    $TPL->assign("ActionInfo", date("Y-m-d H:i") . " " . $Action . $ActionDesc . " By ".$ActionUser);
    $TPL->assign("Notes",sysStripSlash($Notes));    // Because the Notes are $_POST vars and has formatted  by addslashes(), so strip the slahes here.

    // Get change info in html.
    return ($TPL->fetch("MailChange.tpl"));
}


/**
 * Set multi info about buglist
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $BugList
 * @param    array  $UserNameList
 * @param    array  $GroupNameList
 * @return   array  $BugList
 */
function testSetBugListMultiInfo($BugList, $UserNameList = '', $GroupNameList = '')
{
      foreach($BugList as $Key => $BugInfo)
      {
            $BugList[$Key] = testSetBugMultiInfo($BugInfo, $UserNameList, $GroupNameList);
      }
      return $BugList;
}


/**
 * Set multi info about bug
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $BugInfo
 * @param    array  $UserNameList
 * @param    array  $GroupNameList
 * @return   array  $BugList
 */
function testSetBugMultiInfo($BugInfo, $UserNameList = '', $GroupNameList = '')
{
        if($BugInfo['OpenedBy'] != '')
        {
            $BugInfo['OpenedByName'] = $UserNameList[$BugInfo['OpenedBy']] == '' ? $BugInfo['OpenedBy'] : $UserNameList[$BugInfo['OpenedBy']];
        }
        if($BugInfo['AssignedTo'] != '')
        {
            $BugInfo['AssignedToName'] = $UserNameList[$BugInfo['AssignedTo']] == '' ? $BugInfo['AssignedTo'] : $UserNameList[$BugInfo['AssignedTo']];
        }
        if($BugInfo['AssignedToDepartment'] != '')
        {
            $BugInfo['AssignedToDepartmentName'] = $GroupNameList[$BugInfo['AssignedToDepartment']] == '' ? $BugInfo['AssignedToDepartment'] : $GroupNameList[$BugInfo['AssignedToDepartment']];
        }
        if($BugInfo['OpenedByDepartment'] != '')
        {
            $BugInfo['OpenedByDepartmentName'] = $GroupNameList[$BugInfo['OpenedByDepartment']] == '' ? $BugInfo['OpenedByDepartment'] : $GroupNameList[$BugInfo['OpenedByDepartment']];
        }
        if($BugInfo['ResolvedBy'] != '')
        {
            $BugInfo['ResolvedByName'] = $UserNameList[$BugInfo['ResolvedBy']] == '' ? $BugInfo['ResolvedBy'] : $UserNameList[$BugInfo['ResolvedBy']];
        }
        if($BugInfo['ClosedBy'] != '')
        {
            $BugInfo['ClosedByName'] = $UserNameList[$BugInfo['ClosedBy']] == '' ? $BugInfo['ClosedBy'] : $UserNameList[$BugInfo['ClosedBy']];
        }
        if($BugInfo['LastEditedBy'] != '')
        {
            $BugInfo['LastEditedByName'] = $UserNameList[$BugInfo['LastEditedBy']] == '' ? $BugInfo['LastEditedBy'] : $UserNameList[$BugInfo['LastEditedBy']];
        }

        if($BugInfo['MailTo'] != '')
        {
              $BugInfo['MailToName'] = testGetMailToList($BugInfo['MailTo']);
              $BugInfo['MailToName'] = @join(',',$BugInfo['MailToName']['RealName']);
        }
        else
        {
            $BugInfo['MailToName'] = '';
        }

        if($BugInfo['BugTitle'] != '')
        {
            $UCTitleLength = 24-strlen($BugInfo['BugID']);
            $ListTitleLength = 50;
            $BugInfo['UCTitle'] = sysSubStr($BugInfo['BugTitle'], $UCTitleLength, true);
            $BugInfo['ListTitle'] = sysSubStr($BugInfo['BugTitle'], $ListTitleLength, true);
        }
        if($BugInfo['BugProjectName'] != '')
        {
            $ListTitleLength = 50;
            $BugInfo['BugProjectNameName'] = sysSubStr($BugInfo['BugProjectName'], $ListTitleLength, true);
        }
				
				//Get ConnectedChangeIDList
        if($BugInfo['ChangeID'] != '')
        {
        		Rainy_Debug($BugInfo['ChangeID'],__FUNCTION__,__LINE__,__FILE__);
            $BugInfo['ChangeIDName'] = preg_replace("/,$/","", $BugInfo['ChangeID']);
        		Rainy_Debug($BugInfo['ChangeIDName'],__FUNCTION__,__LINE__,__FILE__);
            $ChangeList = getChangeTitleArr($BugInfo['ChangeID']);
            Rainy_Debug($ChangeList,__FUNCTION__,__LINE__,__FILE__);
            $BugInfo['ChangeIDList'] = $ChangeList;
        }
        
        //If Bug is Duplicated With Others Bug, Status should use that SR's status
        Rainy_Debug($BugInfo['IsDuplicated'],__FUNCTION__,__LINE__,__FILE__);
        /*if($BugInfo['IsDuplicated'] == 'Duplicate')
        {
        		$TempBugInfo = GetRawBugInfo($BugInfo['DuplicateID']);
        		if($TempBugInfo['BugStatus'])
        		{
        			$BugInfo['BugStatus'] = $TempBugInfo['BugStatus'];
        		}
        }*/

        $BugInfo = testSetBugInfoLangName($BugInfo);

        return $BugInfo;
}


/**
 * Get buginfo name from $_LANG
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 */
function testSetBugInfoLangName($BugInfo)
{
    global $_LANG;

		if(isset($BugInfo['BugID']))
	  {
    		$BugInfo['BugIDName'] = $_LANG['BugIDPrefix'].$BugInfo['BugID'];
    }
    if(isset($BugInfo['BugSeverity']))
    {
        $BugInfo['BugSeverityName'] = $_LANG['BugSeveritys'][$BugInfo['BugSeverity']];
    }
    if(isset($BugInfo['BugPriority']))
    {
        $BugInfo['BugPriorityName'] = $_LANG['BugPriorities'][$BugInfo['BugPriority']];
    }
    if(isset($BugInfo['BugType']))
    {
        $BugInfo['BugTypeName'] = $_LANG['BugTypes'][$BugInfo['BugType']];
    }
    if(isset($BugInfo['BugOS']))
    {
        $BugInfo['BugOSName'] = $_LANG['BugOS'][$BugInfo['BugOS']];
    }
    if(isset($BugInfo['BugBrowser']))
    {
        $BugInfo['BugBrowserName'] = $_LANG['BugBrowser'][$BugInfo['BugBrowser']];
    }
    if(isset($BugInfo['BugMachine']))
    {
        $BugInfo['BugMachineName'] = $_LANG['BugMachine'][$BugInfo['BugMachine']];
    }
    if(isset($BugInfo['BugSubStatus']))
    {
        $BugInfo['BugSubStatusName'] = $_LANG['BugSubStatus'][$BugInfo['BugSubStatus']];
    }
    if(isset($BugInfo['HowFound']))
    {
        $BugInfo['HowFoundName'] = $_LANG['BugHowFound'][$BugInfo['HowFound']];
    }
    if(isset($BugInfo['BugStatus']))
    {
        $BugInfo['BugStatusName'] = $_LANG['BugStatus'][$BugInfo['BugStatus']];
        $BugInfo['BugStatusColor'] = $_LANG['BugStatusColors'][$BugInfo['BugStatus']];
    }
    if(isset($BugInfo['Resolution']))
    {
        $BugInfo['ResolutionName'] = $_LANG['BugResolutions'][$BugInfo['Resolution']];
    }

    return $BugInfo;
}

/*=======================================Bug Functions End==============================*/

/*=======================================Change Funtions Start=========================================*/

/**
 * Set multi info about changelist
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ChangeList
 * @param    array  $UserNameList
 * @return   array  $ChangeList
 */
function testSetChangeListMultiInfo($ChangeList, $UserNameList = '')
{
      foreach($ChangeList as $Key => $ChangeInfo)
      {
            $ChangeList[$Key] = testSetChangeMultiInfo($ChangeInfo, $UserNameList);
      }
      return $ChangeList;
}

/**
 * Set multi info about Change
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ChangeInfo
 * @param    array  $UserNameList
 * @return   array  $ChangeList
 */
function testSetChangeMultiInfo($ChangeInfo, $UserNameList = '')
{
        if($ChangeInfo['OpenedBy'] != '')
        {
            $ChangeInfo['OpenedByName'] = $UserNameList[$ChangeInfo['OpenedBy']] == '' ? $ChangeInfo['OpenedBy'] : $UserNameList[$ChangeInfo['OpenedBy']];
        }
        if($ChangeInfo['AssignedTo'] != '')
        {
            $ChangeInfo['AssignedToName'] = $UserNameList[$ChangeInfo['AssignedTo']] == '' ? $ChangeInfo['AssignedTo'] : $UserNameList[$ChangeInfo['AssignedTo']];
        }
        if($ChangeInfo['ResolvedBy'] != '')
        {
            $ChangeInfo['ResolvedByName'] = $UserNameList[$ChangeInfo['ResolvedBy']] == '' ? $ChangeInfo['ResolvedBy'] : $UserNameList[$ChangeInfo['ResolvedBy']];
        }
        if($ChangeInfo['ClosedBy'] != '')
        {
            $ChangeInfo['ClosedByName'] = $UserNameList[$ChangeInfo['ClosedBy']] == '' ? $ChangeInfo['ClosedBy'] : $UserNameList[$ChangeInfo['ClosedBy']];
        }
        if($ChangeInfo['LastEditedBy'] != '')
        {
            $ChangeInfo['LastEditedByName'] = $UserNameList[$ChangeInfo['LastEditedBy']] == '' ? $ChangeInfo['LastEditedBy'] : $UserNameList[$ChangeInfo['LastEditedBy']];
        }

        if($ChangeInfo['MailTo'] != '')
        {
              $ChangeInfo['MailToName'] = testGetMailToList($ChangeInfo['MailTo']);
              $ChangeInfo['MailToName'] = @join(',',$ChangeInfo['MailToName']['RealName']);
        }
        else
        {
            $ChangeInfo['MailToName'] = '';
        }

        if($ChangeInfo['ChangeTitle'] != '')
        {
            $UCTitleLength = 24-strlen($ChangeInfo['ChangeID']);
            $ListTitleLength = 50;
            $ChangeInfo['UCTitle'] = sysSubStr($ChangeInfo['ChangeTitle'], $UCTitleLength, true);
            $ChangeInfo['ListTitle'] = sysSubStr($ChangeInfo['ChangeTitle'], $ListTitleLength, true);
        }
        if($ChangeInfo['ChangeProjectName'] != '')
        {
            $ListTitleLength = 50;
            $ChangeInfo['ChangeProjectNameName'] = sysSubStr($ChangeInfo['ChangeProjectName'], $ListTitleLength, true);
        }
				
				//Get ConnectedReviewIDList
        if($ChangeInfo['ReviewID'] != '')
        {
        		Rainy_Debug($ChangeInfo['ReviewID'],__FUNCTION__,__LINE__,__FILE__);
            $ChangeInfo['ReviewIDName'] = preg_replace("/,$/","", $ChangeInfo['ReviewID']);
        		Rainy_Debug($ChangeInfo['ReviewIDName'],__FUNCTION__,__LINE__,__FILE__);
            $ReviewList = getReviewTitleArr($ChangeInfo['ReviewID']);
            Rainy_Debug($ReviewList,__FUNCTION__,__LINE__,__FILE__);
            $ChangeInfo['ReviewIDList'] = $ReviewList;
        }

        $ChangeInfo = testSetChangeInfoLangName($ChangeInfo);

        return $ChangeInfo;
}

/**
 * Get buginfo name from $_LANG
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 */
function testSetChangeInfoLangName($ChangeInfo)
{
    global $_LANG;
		
		if(isset($ChangeInfo['ChangeID']))
	  {
    		$ChangeInfo['ChangeIDName'] = $_LANG['ChangeIDPrefix'].$ChangeInfo['ChangeID'];
    }
    if(isset($ChangeInfo['ChangeType']))
    {
        $ChangeInfo['ChangeTypeName'] = $_LANG['ChangeTypes'][$ChangeInfo['ChangeType']];
    }
    if(isset($ChangeInfo['ChangeStatus']))
    {
        $ChangeInfo['ChangeStatusName'] = $_LANG['ChangeStatus'][$ChangeInfo['ChangeStatus']];
        $ChangeInfo['ChangeStatusColor'] = $_LANG['ChangeStatusColors'][$ChangeInfo['ChangeStatus']];
    }

    return $ChangeInfo;
}

/*=======================================Change Funtions End=========================================*/

/*=======================================Review Funtions Start=========================================*/

/**
 * Set multi info about reviewlist
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ReviewList
 * @param    array  $UserNameList
 * @return   array  $ReviewList
 */
function testSetReviewListMultiInfo($ReviewList, $UserNameList = '')
{
      foreach($ReviewList as $Key => $ReviewInfo)
      {
            $ReviewList[$Key] = testSetReviewMultiInfo($ReviewInfo, $UserNameList);
      }
      return $ReviewList;
}

/**
 * Set multi info about Review
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ReviewInfo
 * @param    array  $UserNameList
 * @return   array  $ReviewInfo
 */
function testSetReviewMultiInfo($ReviewInfo, $UserNameList = '')
{
        if($ReviewInfo['OpenedBy'] != '')
        {
            $ReviewInfo['OpenedByName'] = $UserNameList[$ReviewInfo['OpenedBy']] == '' ? $ReviewInfo['OpenedBy'] : $UserNameList[$ReviewInfo['OpenedBy']];
        }
        if($ReviewInfo['ResolvedBy'] != '')
        {
            $ReviewInfo['ResolvedByName'] = $UserNameList[$ReviewInfo['ResolvedBy']] == '' ? $ReviewInfo['ResolvedBy'] : $UserNameList[$ReviewInfo['ResolvedBy']];
        }
        if($ReviewInfo['ClosedBy'] != '')
        {
            $ReviewInfo['ClosedByName'] = $UserNameList[$ReviewInfo['ClosedBy']] == '' ? $ReviewInfo['ClosedBy'] : $UserNameList[$ReviewInfo['ClosedBy']];
        }
        if($ReviewInfo['LastEditedBy'] != '')
        {
            $ReviewInfo['LastEditedByName'] = $UserNameList[$ReviewInfo['LastEditedBy']] == '' ? $ReviewInfo['LastEditedBy'] : $UserNameList[$ReviewInfo['LastEditedBy']];
        }

        if($ReviewInfo['MailTo'] != '')
        {
              $ReviewInfo['MailToName'] = testGetMailToList($ReviewInfo['MailTo']);
              $ReviewInfo['MailToName'] = @join(',',$ReviewInfo['MailToName']['RealName']);
        }
        else
        {
            $ReviewInfo['MailToName'] = '';
        }

        if($ReviewInfo['Author'] != '')
        {
            $ReviewInfo['AuthorName'] = $UserNameList[$ReviewInfo['Author']] == '' ? $ReviewInfo['Author'] : $UserNameList[$ReviewInfo['Author']];
        }
        if($ReviewInfo['Moderator'] != '')
        {
            $ReviewInfo['ModeratorName'] = $UserNameList[$ReviewInfo['Moderator']] == '' ? $ReviewInfo['Moderator'] : $UserNameList[$ReviewInfo['Moderator']];
        }
        if($ReviewInfo['Recorder'] != '')
        {
            $ReviewInfo['RecorderName'] = $UserNameList[$ReviewInfo['Recorder']] == '' ? $ReviewInfo['Recorder'] : $UserNameList[$ReviewInfo['Recorder']];
        }

        if($ReviewInfo['Inspectors'] != '')
        {
              $ReviewInfo['InspectorsName'] = testGetMailToList($ReviewInfo['Inspectors']);
              $ReviewInfo['InspectorsName'] = @join(',',$ReviewInfo['InspectorsName']['RealName']);
        }
        else
        {
            $ReviewInfo['InspectorsName'] = '';
        }
        if($ReviewInfo['ReviewTitle'] != '')
        {
            $UCTitleLength = 24-strlen($ReviewInfo['ReviewID']);
            $ListTitleLength = 50;
            $ReviewInfo['UCTitle'] = sysSubStr($ReviewInfo['ReviewTitle'], $UCTitleLength, true);
            $ReviewInfo['ListTitle'] = sysSubStr($ReviewInfo['ReviewTitle'], $ListTitleLength, true);
        }
        if($ReviewInfo['ReviewProjectName'] != '')
        {
            $ListTitleLength = 50;
            $ReviewInfo['ReviewProjectNameName'] = sysSubStr($ReviewInfo['ReviewProjectName'], $ListTitleLength, true);
        }

				//Get ConnectedReviewCommentIDList
        if($ReviewInfo['ReviewCommentID'] != '')
        {
        		Rainy_Debug($ReviewInfo['ReviewCommentID'],__FUNCTION__,__LINE__,__FILE__);
            $ReviewInfo['ReviewCommentIDName'] = preg_replace("/,$/","", $ReviewInfo['ReviewCommentID']);
        		Rainy_Debug($ReviewInfo['ReviewCommentIDName'],__FUNCTION__,__LINE__,__FILE__);
            $ReviewCommentList = getReviewCommentTitleArr($ReviewInfo['ReviewCommentID']);
            Rainy_Debug($ReviewCommentList,__FUNCTION__,__LINE__,__FILE__);
            $ReviewInfo['ReviewCommentIDList'] = $ReviewCommentList;
        }

        $ReviewInfo = testSetReviewInfoLangName($ReviewInfo);

        return $ReviewInfo;
}

/**
 * Get reviewinfo name from $_LANG
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 */
function testSetReviewInfoLangName($ReviewInfo)
{
    global $_LANG;

		if(isset($ReviewInfo['ReviewID']))
	  {
    		$ReviewInfo['ReviewIDName'] = $_LANG['ReviewIDPrefix'].$ReviewInfo['ReviewID'];
    }
    if(isset($ReviewInfo['ReviewType']))
    {
        $ReviewInfo['ReviewTypeName'] = $_LANG['ReviewTypes'][$ReviewInfo['ReviewType']];
    }
    if(isset($ReviewInfo['ReviewConclusion']))
    {
        $ReviewInfo['ReviewConclusionName'] = $_LANG['ReviewConclusions'][$ReviewInfo['ReviewConclusion']];
    }
    if(isset($ReviewInfo['StartTime']))
    {
        $ReviewInfo['StartTimeName'] = $_LANG['TimeList'][$ReviewInfo['StartTime']];
    }
    if(isset($ReviewInfo['EndTime']))
    {
        $ReviewInfo['EndTimeName'] = $_LANG['TimeList'][$ReviewInfo['EndTime']];
    }
    if(isset($ReviewInfo['ReviewStatus']))
    {
        $ReviewInfo['ReviewStatusName'] = $_LANG['ReviewStatus'][$ReviewInfo['ReviewStatus']];
        $ReviewInfo['ReviewStatusColor'] = $_LANG['ReviewStatusColors'][$ReviewInfo['ReviewStatus']];
    }

    return $ReviewInfo;
}

/*=======================================Review Funtions End=========================================*/
/*=======================================ReviewComment Funtions Start=========================================*/

/**
 * Set multi info about reviewcommentlist
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ReviewCommentList
 * @param    array  $UserNameList
 * @return   array  $ReviewCommentList
 */
function testSetReviewCommentListMultiInfo($ReviewCommentList, $UserNameList = '')
{
      foreach($ReviewCommentList as $Key => $ReviewCommentInfo)
      {
            $ReviewCommentList[$Key] = testSetReviewCommentMultiInfo($ReviewCommentInfo, $UserNameList);
      }
      return $ReviewCommentList;
}

/**
 * Set multi info about ReviewComment
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $ReviewCommentInfo
 * @param    array  $UserNameList
 * @return   array  $ReviewCommentInfo
 */
function testSetReviewCommentMultiInfo($ReviewCommentInfo, $UserNameList = '')
{
        if($ReviewCommentInfo['OpenedBy'] != '')
        {
            $ReviewCommentInfo['OpenedByName'] = $UserNameList[$ReviewCommentInfo['OpenedBy']] == '' ? $ReviewCommentInfo['OpenedBy'] : $UserNameList[$ReviewCommentInfo['OpenedBy']];
        }
        if($ReviewCommentInfo['ResolvedBy'] != '')
        {
            $ReviewCommentInfo['ResolvedByName'] = $UserNameList[$ReviewCommentInfo['ResolvedBy']] == '' ? $ReviewCommentInfo['ResolvedBy'] : $UserNameList[$ReviewCommentInfo['ResolvedBy']];
        }
        if($ReviewCommentInfo['ClosedBy'] != '')
        {
            $ReviewCommentInfo['ClosedByName'] = $UserNameList[$ReviewCommentInfo['ClosedBy']] == '' ? $ReviewCommentInfo['ClosedBy'] : $UserNameList[$ReviewCommentInfo['ClosedBy']];
        }
        if($ReviewCommentInfo['LastEditedBy'] != '')
        {
            $ReviewCommentInfo['LastEditedByName'] = $UserNameList[$ReviewCommentInfo['LastEditedBy']] == '' ? $ReviewCommentInfo['LastEditedBy'] : $UserNameList[$ReviewCommentInfo['LastEditedBy']];
        }
        
        if($ReviewCommentInfo['ReviewCommentOwner'] != '')
        {
            $ReviewCommentInfo['ReviewCommentOwnerName'] = $UserNameList[$ReviewCommentInfo['ReviewCommentOwner']] == '' ? $ReviewCommentInfo['ReviewCommentOwner'] : $UserNameList[$ReviewCommentInfo['ReviewCommentOwner']];
        }

        if($ReviewCommentInfo['MailTo'] != '')
        {
              $ReviewCommentInfo['MailToName'] = testGetMailToList($ReviewCommentInfo['MailTo']);
              $ReviewCommentInfo['MailToName'] = @join(',',$ReviewCommentInfo['MailToName']['RealName']);
        }
        else
        {
            $ReviewCommentInfo['MailToName'] = '';
        }

        if($ReviewCommentInfo['ReviewCommentTitle'] != '')
        {
            $UCTitleLength = 24-strlen($ReviewCommentInfo['ReviewCommentID']);
            $ListTitleLength = 50;
            $ReviewCommentInfo['UCTitle'] = sysSubStr($ReviewCommentInfo['ReviewCommentTitle'], $UCTitleLength, true);
            $ReviewCommentInfo['ListTitle'] = sysSubStr($ReviewCommentInfo['ReviewCommentTitle'], $ListTitleLength, true);
        }
        if($ReviewCommentInfo['ReviewCommentProjectName'] != '')
        {
            $ListTitleLength = 50;
            $ReviewCommentInfo['ReviewCommentProjectNameName'] = sysSubStr($ReviewCommentInfo['ReviewCommentProjectName'], $ListTitleLength, true);
        }

        $ReviewCommentInfo = testSetReviewCommentInfoLangName($ReviewCommentInfo);

        return $ReviewCommentInfo;
}

/**
 * Get reviewCommentinfo name from $_LANG
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 */
function testSetReviewCommentInfoLangName($ReviewCommentInfo)
{
    global $_LANG;

		if(isset($ReviewCommentInfo['ReviewCommentID']))
	  {
    		$ReviewCommentInfo['ReviewCommentIDName'] = $_LANG['ReviewCommentIDPrefix'].$ReviewCommentInfo['ReviewCommentID'];
    }
    if(isset($ReviewCommentInfo['ReviewCommentType']))
    {
        $ReviewCommentInfo['ReviewCommentTypeName'] = $_LANG['ReviewCommentTypes'][$ReviewCommentInfo['ReviewCommentType']];
    }
    if(isset($ReviewCommentInfo['ReviewCommentStatus']))
    {
        $ReviewCommentInfo['ReviewCommentStatusName'] = $_LANG['ReviewCommentStatus'][$ReviewCommentInfo['ReviewCommentStatus']];
        $ReviewCommentInfo['ReviewCommentStatusColor'] = $_LANG['ReviewCommentStatusColors'][$ReviewCommentInfo['ReviewCommentStatus']];
    }
    
    //Get ReviewInfo and Set ReviewType
		$ReviewID = $ReviewCommentInfo['ReviewID'];
		$ReviewInfo = GetRawReviewInfo($ReviewID);
		$ReviewType = $ReviewInfo['ReviewType'] != ''? $ReviewInfo['ReviewType']: 'Others';
		$ReviewCommentInfo['ReviewType'] = $ReviewType;
		$ReviewCommentInfo['ReviewCommentPos1Name'] = $_LANG['ReviewCommentPos1Names'][$ReviewType];
		$ReviewCommentInfo['ReviewCommentPos2Name'] = $_LANG['ReviewCommentPos2Names'][$ReviewType];
		$ReviewCommentInfo['ReviewCommentPos3Name'] = $_LANG['ReviewCommentPos3Names'][$ReviewType];
		Rainy_Debug($ReviewCommentInfo,__FUNCTION__,__LINE__,__FILE__);
		
    return $ReviewCommentInfo;
}

/*=======================================ReviewComment Funtions End=========================================*/
/*=======================================Plan Funtions Start=========================================*/

/**
 * Set multi info about Planlist
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $PlanList
 * @param    array  $UserNameList
 * @return   array  $PlanList
 */
function testSetPlanListMultiInfo($PlanList, $UserNameList = '')
{
      foreach($PlanList as $Key => $PlanInfo)
      {
            $PlanList[$Key] = testSetPlanMultiInfo($PlanInfo, $UserNameList);
      }
      return $PlanList;
}

/**
 * Set multi info about Plan
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $PlanInfo
 * @param    array  $UserNameList
 * @return   array  $PlanInfo
 */
function testSetPlanMultiInfo($PlanInfo, $UserNameList = '')
{
        if($PlanInfo['OpenedBy'] != '')
        {
            $PlanInfo['OpenedByName'] = $UserNameList[$PlanInfo['OpenedBy']] == '' ? $PlanInfo['OpenedBy'] : $UserNameList[$PlanInfo['OpenedBy']];
        }
        if($PlanInfo['ResolvedBy'] != '')
        {
            $PlanInfo['ResolvedByName'] = $UserNameList[$PlanInfo['ResolvedBy']] == '' ? $PlanInfo['ResolvedBy'] : $UserNameList[$PlanInfo['ResolvedBy']];
        }
        if($PlanInfo['ClosedBy'] != '')
        {
            $PlanInfo['ClosedByName'] = $UserNameList[$PlanInfo['ClosedBy']] == '' ? $PlanInfo['ClosedBy'] : $UserNameList[$PlanInfo['ClosedBy']];
        }
        if($PlanInfo['LastEditedBy'] != '')
        {
            $PlanInfo['LastEditedByName'] = $UserNameList[$PlanInfo['LastEditedBy']] == '' ? $PlanInfo['LastEditedBy'] : $UserNameList[$PlanInfo['LastEditedBy']];
        }

        if($PlanInfo['MailTo'] != '')
        {
              $PlanInfo['MailToName'] = testGetMailToList($PlanInfo['MailTo']);
              $PlanInfo['MailToName'] = @join(',',$PlanInfo['MailToName']['RealName']);
        }
        else
        {
            $PlanInfo['MailToName'] = '';
        }

        if($PlanInfo['Author'] != '')
        {
            $PlanInfo['AuthorName'] = $UserNameList[$PlanInfo['Author']] == '' ? $PlanInfo['Author'] : $UserNameList[$PlanInfo['Author']];
        }
        if($PlanInfo['Moderator'] != '')
        {
            $PlanInfo['ModeratorName'] = $UserNameList[$PlanInfo['Moderator']] == '' ? $PlanInfo['Moderator'] : $UserNameList[$PlanInfo['Moderator']];
        }
        if($PlanInfo['Recorder'] != '')
        {
            $PlanInfo['RecorderName'] = $UserNameList[$PlanInfo['Recorder']] == '' ? $PlanInfo['Recorder'] : $UserNameList[$PlanInfo['Recorder']];
        }

        if($PlanInfo['Inspectors'] != '')
        {
              $PlanInfo['InspectorsName'] = testGetMailToList($PlanInfo['Inspectors']);
              $PlanInfo['InspectorsName'] = @join(',',$PlanInfo['InspectorsName']['RealName']);
        }
        else
        {
            $PlanInfo['InspectorsName'] = '';
        }
        if($PlanInfo['PlanTitle'] != '')
        {
            $UCTitleLength = 24-strlen($PlanInfo['PlanID']);
            $ListTitleLength = 50;
            $PlanInfo['UCTitle'] = sysSubStr($PlanInfo['PlanTitle'], $UCTitleLength, true);
            $PlanInfo['ListTitle'] = sysSubStr($PlanInfo['PlanTitle'], $ListTitleLength, true);
        }
        if($PlanInfo['PlanProjectName'] != '')
        {
            $ListTitleLength = 50;
            $PlanInfo['PlanProjectNameName'] = sysSubStr($PlanInfo['PlanProjectName'], $ListTitleLength, true);
        }

				//Get ConnectedPlanCommentIDList
        if($PlanInfo['PlanCommentID'] != '')
        {
        		Rainy_Debug($PlanInfo['PlanCommentID'],__FUNCTION__,__LINE__,__FILE__);
            $PlanInfo['PlanCommentIDName'] = preg_replace("/,$/","", $PlanInfo['PlanCommentID']);
        		Rainy_Debug($PlanInfo['PlanCommentIDName'],__FUNCTION__,__LINE__,__FILE__);
            $PlanCommentList = getPlanCommentTitleArr($PlanInfo['PlanCommentID']);
            Rainy_Debug($PlanCommentList,__FUNCTION__,__LINE__,__FILE__);
            $PlanInfo['PlanCommentIDList'] = $PlanCommentList;
        }

        $PlanInfo = testSetPlanInfoLangName($PlanInfo);

        return $PlanInfo;
}

/**
 * Get Planinfo name from $_LANG
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 */
function testSetPlanInfoLangName($PlanInfo)
{
    global $_LANG;

		if(isset($PlanInfo['PlanID']))
	  {
    		$PlanInfo['PlanIDName'] = $_LANG['PlanIDPrefix'].$PlanInfo['PlanID'];
    }
    if(isset($PlanInfo['PlanType']))
    {
        $PlanInfo['PlanTypeName'] = $_LANG['PlanTypes'][$PlanInfo['PlanType']];
    }
    if(isset($PlanInfo['PlanConclusion']))
    {
        $PlanInfo['PlanConclusionName'] = $_LANG['PlanConclusions'][$PlanInfo['PlanConclusion']];
    }
    if(isset($PlanInfo['StartTime']))
    {
        $PlanInfo['StartTimeName'] = $_LANG['TimeList'][$PlanInfo['StartTime']];
    }
    if(isset($PlanInfo['EndTime']))
    {
        $PlanInfo['EndTimeName'] = $_LANG['TimeList'][$PlanInfo['EndTime']];
    }
    if(isset($PlanInfo['PlanStatus']))
    {
        $PlanInfo['PlanStatusName'] = $_LANG['PlanStatus'][$PlanInfo['PlanStatus']];
        $PlanInfo['PlanStatusColor'] = $_LANG['PlanStatusColors'][$PlanInfo['PlanStatus']];
    }

    return $PlanInfo;
}

/*=======================================Plan Funtions End=========================================*/
/*=======================================Case Funtions Start=========================================*/

/**
 * Set multi info about case
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array $CaseInfo
 * @param  array $UserNameList
 * @return array $CaseInfo
 */
function testSetCaseMultiInfo($CaseInfo, $UserNameList = '')
{
        if($CaseInfo['OpenedBy'] != '')
        {
            $CaseInfo['OpenedByName'] = $UserNameList[$CaseInfo['OpenedBy']] == '' ? $CaseInfo['OpenedBy'] : $UserNameList[$CaseInfo['OpenedBy']];
        }
        if($CaseInfo['AssignedTo'] != '')
        {
            $CaseInfo['AssignedToName'] = $UserNameList[$CaseInfo['AssignedTo']] == '' ? $CaseInfo['AssignedTo'] : $UserNameList[$CaseInfo['AssignedTo']];
        }
        if($CaseInfo['LastEditedBy'] != '')
        {
            $CaseInfo['LastEditedByName'] = $UserNameList[$CaseInfo['LastEditedBy']] == '' ? $CaseInfo['LastEditedBy'] : $UserNameList[$CaseInfo['LastEditedBy']];
        }
        if($CaseInfo['ScriptedBy'] != '')
        {
            $CaseInfo['ScriptedByName'] = $UserNameList[$CaseInfo['ScriptedBy']] == '' ? $CaseInfo['ScriptedBy'] : $UserNameList[$CaseInfo['ScriptedBy']];
        }

        if($CaseInfo['MailTo'] != '')
        {
              $CaseInfo['MailToName'] = testGetMailToList($CaseInfo['MailTo']);
              $CaseInfo['MailToName'] = @join(',',$CaseInfo['MailToName']['RealName']);
        }
        else
        {
            $CaseInfo['MailToName'] = '';
        }

        if($CaseInfo['CaseTitle'] != '')
        {
            $UCTitleLength = 24-strlen($CaseInfo['CaseID']);
            $ListTitleLength = 50;
            $CaseInfo['UCTitle'] = sysSubStr($CaseInfo['CaseTitle'], $UCTitleLength, true);
            $CaseInfo['ListTitle'] = sysSubStr($CaseInfo['CaseTitle'], $ListTitleLength, true);
        }
        if($CaseInfo['ResultID'] != '')
        {
            $CaseInfo['ResultIDName'] = preg_replace("/,$/","", $CaseInfo['ResultID']);
            $ResultList = getResultTitleArr($CaseInfo['ResultID']);
            $CaseInfo['ResultIDList'] = $ResultList;
                }

        $CaseInfo = testSetCaseInfoLangName($CaseInfo);

        return $CaseInfo;
}

/**
 * Get caseinfo name from $_LANG
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 */
function testSetCaseInfoLangName($CaseInfo)
{
    global $_LANG;

    if(isset($CaseInfo['CasePriority']))
    {
        $CaseInfo['CasePriorityName'] = $_LANG['CasePriorities'][$CaseInfo['CasePriority']];
    }
    if(isset($CaseInfo['CaseType']))
    {
        $CaseInfo['CaseTypeName'] = $_LANG['CaseTypes'][$CaseInfo['CaseType']];
    }
    if(isset($CaseInfo['CaseStatus']))
    {
        $CaseInfo['CaseStatusName'] = $_LANG['CaseStatuses'][$CaseInfo['CaseStatus']];
    }
    if(isset($CaseInfo['CaseMethod']))
    {
        $CaseInfo['CaseMethodName'] = $_LANG['CaseMethods'][$CaseInfo['CaseMethod']];
    }
    if(isset($CaseInfo['CasePlan']))
    {
        $CaseInfo['CasePlanName'] = $_LANG['CasePlans'][$CaseInfo['CasePlan']];
    }
    if(isset($CaseInfo['MarkForDeletion']))
    {
        $CaseInfo['MarkForDeletionName'] = $_LANG['MarkForDeletions'][$CaseInfo['MarkForDeletion']];
    }
    if(isset($CaseInfo['ScriptStatus']))
    {
        $CaseInfo['ScriptStatusName'] = $_LANG['ScriptStatuses'][$CaseInfo['ScriptStatus']];
    }
    return $CaseInfo;
}

/**
 * Set multi info about case list
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array $CaseList
 * @param  array $UserNameList
 * @return array $CaseList
 */
function testSetCaseListMultiInfo($CaseList, $UserNameList = '')
{
      foreach($CaseList as $Key => $CaseInfo)
      {
            $CaseList[$Key] = testSetCaseMultiInfo($CaseInfo, $UserNameList);
      }
      return $CaseList;
}
/*=======================================Case Funtions End=========================================*/

/*=======================================Result Functions Start====================================*/
/**
 * Set multi info about result list
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array $ResultList
 * @param  array $UserNameList
 * @return array $ResultList
 */
function testSetResultListMultiInfo($ResultList, $UserNameList = '')
{
      foreach($ResultList as $Key => $ResultInfo)
      {
            $ResultList[$Key] = testSetResultMultiInfo($ResultInfo, $UserNameList);
      }
      return $ResultList;
}

/**
 * Set multi info about result
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param  array $ResultInfo
 * @param  array $UserNameList
 * @return array $ResultInfo
 */
function testSetResultMultiInfo($ResultInfo, $UserNameList = '')
{
        if($ResultInfo['OpenedBy'] != '')
        {
            $ResultInfo['OpenedByName'] = $UserNameList[$ResultInfo['OpenedBy']] == '' ? $ResultInfo['OpenedBy'] : $UserNameList[$ResultInfo['OpenedBy']];
        }
        if($ResultInfo['AssignedTo'] != '')
        {
            $ResultInfo['AssignedToName'] = $UserNameList[$ResultInfo['AssignedTo']] == '' ? $ResultInfo['AssignedTo'] : $UserNameList[$ResultInfo['AssignedTo']];
        }
        if($ResultInfo['LastEditedBy'] != '')
        {
            $ResultInfo['LastEditedByName'] = $UserNameList[$ResultInfo['LastEditedBy']] == '' ? $ResultInfo['LastEditedBy'] : $UserNameList[$ResultInfo['LastEditedBy']];
        }
        if($ResultInfo['ResultTitle'] != '')
        {

            $UCTitleLength = 24-strlen($BugInfo['BugID']);
            $ListTitleLength = 50;
            $ResultInfo['UCTitle'] = sysSubStr($ResultInfo['ResultTitle'], $UCTitleLength, true);
            $ResultInfo['ListTitle'] = sysSubStr($ResultInfo['ResultTitle'], $ListTitleLength, true);
        }

        if($ResultInfo['MailTo'] != '')
        {
              $ResultInfo['MailToName'] = testGetMailToList($ResultInfo['MailTo']);
              $ResultInfo['MailToName'] = @join(',',$ResultInfo['MailToName']['RealName']);
        }
        else
        {
            $ResultInfo['MailToName'] = '';
        }
        if($ResultInfo['BugID'] != '')
        {
            $ResultInfo['BugIDName'] = preg_replace("/,$/","", $ResultInfo['BugID']);
            $BugList = getBugTitleArr($ResultInfo['BugID']);
            $ResultInfo['BugIDList'] = $BugList;
        }
        if($ResultInfo['CaseID'] != '')
            {
            $ResultInfo['CaseID'] = preg_replace("/,$/","", $ResultInfo['CaseID']);
            $CaseList = getCaseTitleArr($ResultInfo['CaseID']);
            $ResultInfo['CaseTitle'] = $CaseList[$ResultInfo['CaseID']];
                }

        $ResultInfo = testSetResultInfoLangName($ResultInfo);

        return $ResultInfo;
}

/**
 * Get Resultinfo name from $_LANG
 *
 * @author                   Yupeng Lee<leeyupeng@gmail.com>
 */
function testSetResultInfoLangName($ResultInfo)
{
    global $_LANG;

    if(isset($ResultInfo['ResultValue']))
    {
        $ResultInfo['ResultValueName'] = $_LANG['ResultValues'][$ResultInfo['ResultValue']];
        $ResultInfo['ResultValueColor'] = $_LANG['ResultValueColors'][$ResultInfo['ResultValue']];
    }
    if(isset($ResultInfo['ResultOS']))
    {
        $ResultInfo['ResultOSName'] = $_LANG['ResultOS'][$ResultInfo['ResultOS']];
    }
    if(isset($ResultInfo['ResultBrowser']))
    {
        $ResultInfo['ResultBrowserName'] = $_LANG['ResultBrowser'][$ResultInfo['ResultBrowser']];
    }
    if(isset($ResultInfo['ResultStatus']))
    {
        $ResultInfo['ResultStatusName'] = $_LANG['ResultStatuses'][$ResultInfo['ResultStatus']];
    }

    return $ResultInfo;
}

/*=======================================Result Function End======================================*/

/*=======================================UserLog Funtions Start=========================================*/

/**
 * Set multi info about reviewlist
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $UserLogList
 * @param    array  $UserNameList
 * @return   array  $UserLogList
 */
function testSetUserLogListMultiInfo($UserLogList, $UserNameList = '')
{
      foreach($UserLogList as $Key => $UserLogInfo)
      {
            $UserLogList[$Key] = testSetUserLogMultiInfo($UserLogInfo, $UserNameList);
      }
      return $UserLogList;
}

/**
 * Set multi info about UserLog
 *
 * @author   Rainy.Gao <zju_rain@163.com>
 * @param    array  $UserLogInfo
 * @param    array  $UserNameList
 * @return   array  $UserLogInfo
 */
function testSetUserLogMultiInfo($UserLogInfo, $UserNameList = '')
{
        if($UserLogInfo['UserName'] != '')
        {
            $UserLogInfo['RealName'] = $UserNameList[$UserLogInfo['UserName']];
        }

        return $UserLogInfo;
}

/*=======================================Review Funtions End=========================================*/
/*=======================================Action & History Functions Start=========================*/

/**
 * Add action
 *
 * @author                           Yupeng Lee<leeyupeng@gmail.com>
 * @param     string  $ActionTarget   Bug Case Result
 * @param     string  $IdValuActionNote
 * @param     string  $ActionUser
 * @param     string  $ActionType    Opened, Edited, Resolved, Closed, Activated
 */
function testAddAction($ActionTarget,$IdValue,$ActionUser,$ActionType,$ActionDate='',$ActionNote='')
{
    $ActionID = dbInsertRow('TestAction', "'{$ActionTarget}','{$IdValue}','{$ActionUser}','{$ActionType}',now(),'{$ActionNote}'",
                            'ActionTarget,IdValue,ActionUser,ActionType,ActionDate,ActionNote');
    return $ActionID;
}

/**
 * Add history
 *
 * @author                            Yupeng Lee<leeyupeng@gmail.com>
 * @param     string   $ActionID
 * @param     string   $ActionField
 * @param     string   $OldValue
 * @param     string   $NewValue
 */
function testAddHistory($ActionID, $ActionField, $OldValue, $NewValue)
{
    $HistoryID = dbInsertRow('TestHistory', "'{$ActionID}','{$ActionField}','" . mysql_real_escape_string($OldValue) . "','" . mysql_real_escape_string($NewValue) . "'",
                                            'ActionID,ActionField,OldValue,NewValue');
    return $HistoryID;
}


/**
 * Get action
 *
 * @author                            Yupeng Lee<leeyupeng@gmail.com>
 * @param     string  $ActionTarget    Bug Case or Result
 * @param     string  $IdValue         BugID CaseID or ResultID
 * @param     string  $ActionOrder     'DESC' or 'ASC' by ActionID
 */
function testGetActionAndFileList($ActionTarget, $IdValue, $ActionOrder = 'DESC')
{
      global $_LANG;
      $ActionList = dbGetList('TestAction', '', "ActionTarget = '{$ActionTarget}' AND IdValue IN ('{$IdValue}')",'', 'ActionID '. $ActionOrder);
      $ReturnActionList = array();
      $ActionCount = count($ActionList);
      $UserList = testGetUserList();

      if($ActionOrder == 'DESC')
      {
          $StartKey = $ActionCount;
          $StepRange = -1;
      }
      elseif($ActionOrder == 'ASC')
      {
          $StartKey = 0;
          $StepRange = 1;
      }
      foreach($ActionList as $Key => $ActionInfo)
      {

          $ActionID = $ActionInfo['ActionID'];

          $ReturnActionList['ActionList'][$StartKey] = $ActionInfo;
          $UserRealName = $UserList[$ActionInfo['ActionUser']]['RealName'];
          $ReturnActionList['ActionList'][$StartKey]['ActionUserName'] = $UserRealName == '' ? $ActionInfo['ActionUser'] : $UserRealName;

          $TmpHistoryList = testGetHistoryList($ActionID);
          foreach($TmpHistoryList as $Key => $HistoryInfo)
          {
              if($HistoryInfo['ActionField'] == 'Resolution')
              {
                  $ReturnActionList['ActionList'][$StartKey]['Resolution'] = $HistoryInfo['NewValue'];
                  //break;
              }

              if($HistoryInfo['ActionField'] == 'MailTo')
              {
                  if($HistoryInfo['OldValue'] != '')
                  {
                      $HistoryInfo['OldValue'] = testGetMailToList($HistoryInfo['OldValue']);
                      $HistoryInfo['OldValue'] = @join(',', $HistoryInfo['OldValue']['RealName']);
                  }
                  if($HistoryInfo['NewValue'] != '')
                  {
                      $HistoryInfo['NewValue'] = testGetMailToList($HistoryInfo['NewValue']);
                      $HistoryInfo['NewValue'] = @join(',', $HistoryInfo['NewValue']['RealName']);
                  }
              }
              // user
              if(array_key_exists($HistoryInfo['OldValue'], $UserList))
              {
                  $HistoryInfo['OldValue'] = $UserList[$HistoryInfo['OldValue']]['RealName'];
              }
              if(array_key_exists($HistoryInfo['NewValue'], $UserList))
              {
                  $HistoryInfo['NewValue'] = $UserList[$HistoryInfo['NewValue']]['RealName'];
              }

              $BugConstantArr = array($_LANG['BugTypes'], $_LANG['BugHowFound']);
              $ConstantArr = array($_LANG['CaseTypes'], $_LANG['CaseMethods'], $_LANG['CasePlans'], $_LANG['ScriptStatuses']);
              if($ActionTarget == 'Bug')
              {
                  $ConstantArr = $BugConstantArr;
              }
              foreach($ConstantArr as $arr)
              {
                  if(array_key_exists($HistoryInfo['OldValue'], $arr))
                  {
                      $HistoryInfo['OldValue'] = $arr[$HistoryInfo['OldValue']];
                  }
                  if(array_key_exists($HistoryInfo['NewValue'], $arr))
                  {
                      $HistoryInfo['NewValue'] = $arr[$HistoryInfo['NewValue']];
                  }
              }

              $TmpHistoryList[$Key]['OldValue'] = $HistoryInfo['OldValue'];
              $TmpHistoryList[$Key]['NewValue'] = $HistoryInfo['NewValue'];

              if(array_key_exists($HistoryInfo['ActionField'], $_LANG[$ActionTarget . 'Fields']))
              {
                  $field = $HistoryInfo['ActionField'];
                  $TmpHistoryList[$Key]['ActionField'] = $_LANG[$ActionTarget . 'Fields']["$field"];
              }
          }
          $ReturnActionList['ActionList'][$StartKey]['HistoryList'] = $TmpHistoryList;

          $TmpActionFileList = testGetActionFileList($ActionID);
          $ReturnActionList['FileList'][$ActionID] = $TmpActionFileList;
          $ReturnActionList['ActionList'][$StartKey]['FileList'] = $ReturnActionList['FileList'][$ActionID];

          $ReturnActionList['ActionList'][$StartKey]['AFCount'] = count($TmpHistoryList)+count($TmpActionFileList);

          $StartKey = $StartKey + $StepRange;
      }

      return $ReturnActionList;
}

/**
 * Get action history list
 *
 * @author                   Yupeng Lee <leeyupeng@gmail.com>
 * @param  int   $ActionID
 * @return array $HistoryList
 */
function testGetHistoryList($ActionID)
{
      $HistoryList = dbGetList('TestHistory', '', "ActionID={$ActionID}");
      return $HistoryList;
}

/**
 * Get last actionid
 *
 * @author                   Yupeng Lee <leeyupeng@gmail.com>
 * @param  string $ActionTarget Bug,Case or Result
 * @param  int    $IdValue
 * @return int    $LastActionID
 */
function testGetLastActionID($ActionTarget, $IdValue)
{
    $LastActionInfo = dbGetList('TestAction', 'ActionID', "ActionTarget='{$ActionTarget}' AND IdValue={$IdValue}",'','ActionID DESC','1');
    $LastActionID = $LastActionInfo[0]['ActionID'] >0 ? $LastActionInfo[0]['ActionID'] : 0;
    return $LastActionID;
}

/*=======================================Aciton Functions End===========================*/

/*======================================File Functions Start============================*/

/**
 * Get action uploaded file list
 *
 * @author                         Yupeng Lee <leeyupeng@gmail.com>
 * @param   int   $ActionID
 * @return  array $FileList
 */
function testGetActionFileList($ActionID)
{
    global $_CFG;
    $FileList = dbGetList('TestFile', '', "ActionID='{$ActionID}'");
    foreach($FileList as $Key => $FileInfo)
    {
        $FileList[$Key]['ForceDownload'] = !@in_array($FileInfo['FileType'], $_CFG['NotForceDownloadFileType']) ? '1' : '0';
    }
    return $FileList;
}

/*======================================File Functions End============================*/

/*=======================================Mail Functions Start==============================*/

/**
 * Get maillist
 *
 * @author                     Yupeng Lee<leeyupeng@gmail.com>
 * @param    string $MailToStr
 * @param    int    $ProjectID
 * @return   array  $ReturnMailList
 */
function testGetMailToList($MailToStr, $ProjectID = 0, $JudgeNotice = false)
{
    $MailToStr = trim($MailToStr);
    $MailToList = explode(',', $MailToStr);
    $ReturnMailList = array();
    $ReturnMailList['MailToArray'] = array();
    if($ProjectID > 0)
    {
        $ProjectUserList = testGetProjectUserList($ProjectID);
    }
    foreach($MailToList as $Key=>$Value)
    {
        $Value = trim($Value);
        if(!empty($Value) && !@in_array($Value,$ReturnMailList['Email']) && !@in_array($Value,$ReturnMailList['MailToArray']))
        {
            if(sysCheckEmailFormat($Value))
            {
                $ReturnMailList['UserName'][$Key] = $Value;
                $ReturnMailList['RealName'][$Key] = $Value;
                $ReturnMailList['Email'][$Key] = $Value;
                $ReturnMailList['MailToArray'][$Key] = $Value;
            }
            else
            {
                $UserInfo = testGetUserInfoByName(mysql_real_escape_string($Value));
                if(!empty($UserInfo) && ($ProjectID == 0 || ($ProjectID > 0  && $ProjectUserList[$UserInfo['UserName']] != '' )))
                {
                    if($JudgeNotice && (($UserInfo['NoticeFlag'] & 2) != 2))
                    {
                        continue;
                    }
                    $ReturnMailList['UserName'][$Key] = $Value;
                    $ReturnMailList['RealName'][$Key] = $UserInfo['RealName'];
                    $ReturnMailList['Email'][$Key] = $UserInfo['Email'];
                    $ReturnMailList['MailToArray'][$Key] = $Value;
                }
            }
        }
    }
    $ReturnMailList['MailToStr'] = join(',', $ReturnMailList['MailToArray']);
    return $ReturnMailList;
}

/*=======================================Mail Functions End==============================*/


/*=======================================Wangwang Functions Start==============================*/
function testGetBugUrl($bugId)
{
    global $_CFG;
    return $_CFG["BaseURL"]  .'/Bug.php?BugID=' . $bugId;
}

/*=======================================Admin Functions Start===========================*/

/**
 * Get project module tree menu html code for admin
 *
 * @author                      Yupeng Lee<leeyupeng@gmail.com>
 * @param   int    $ProjectID
 * @param   string $LinkUrl
 * @param   string $ModuleType  Bug or Case
 * @return  string
 */
function testGetAdminTreeModuleList($ProjectID, $LinkUrl = '', $ModuleType = 'Bug')
{
    $ModuleList = testGetProjectModuleList($ProjectID, $ModuleType);

    $TreeMenuHtml = "<ul>";
    foreach($ModuleList as $ModuleID => $ModuleInfo)
    {
        if($ModuleInfo['IsLeaf'])
        {
            $TreeMenuHtml .= '<li class="ChildNode">';
        }
        else
        {
            $TreeMenuHtml .= '<li class="OpenedNode">';
        }
        if($ModuleInfo['ModuleGrade'] - 0 == 0)
        {
            $TreeMenuHtml .=  "<a href='{$LinkUrl}ProjectID={$ProjectID}&ModuleType={$ModuleType}'><strong>{$ModuleInfo[ModuleName]}</strong></a>";
        }
        else
        {
            $TreeMenuHtml .=  "<a href='{$LinkUrl}ProjectID={$ProjectID}&ModuleType={$ModuleType}&ModuleID={$ModuleID}'>{$ModuleInfo[ModuleName]}</a>";
        }
        if($ModuleInfo['IsLeaf'])
        {
            if($ModuleInfo['IsLastLeaf'])
            {
                $TreeMenuHtml .= str_repeat('</li></ul>', abs($ModuleInfo['ModuleGrade'] - $ModuleList[$ModuleInfo['NextTreeModuleID']]['ModuleGrade'] ));
            }
            else
            {
                $TreeMenuHtml .= '</li>';
            }
        }
        else
        {
            $TreeMenuHtml .= '<ul>';
        }
    }
    return $TreeMenuHtml;
}

function testGetFieldTable($Type, $ProjectID, $HasPreFix = false)
{
    global $_CFG;
    if(!$HasPreFix)
    {
        return strtolower($_CFG['DB']['TablePrefix'] . 'AddOn' . $Type . '_' . $ProjectID);
    }
    else
    {
        return strtolower('AddOn' . $Type . '_' . $ProjectID);
    }
}

function testGetFieldSql($FieldForm)
{
    $sql = '';
    if(is_array($FieldForm))
    {
        $sql .= $FieldForm['FieldName'];
        $FieldForm['FieldValue'] = htmlspecialchars($FieldForm['FieldValue']);
        switch($FieldForm['FieldType'])
        {
            case 'text': {
                $sql .= ' VARCHAR(255) DEFAULT "' . $FieldForm['FieldValue'] . '"';
                break;
            }
            case 'textarea': {
                $sql .= ' TEXT DEFAULT "' . $FieldForm['FieldValue'] . '"';
                break;
            }
            case 'radio':
            case 'select': {
                $sql .= ' ENUM("' . str_replace(',', '","', $FieldForm['FieldValue']) . '")';
                break;
            }
            case 'mulit':
            case 'checkbox': {
                $sql .= ' SET("' . str_replace(',', '","', $FieldForm['FieldValue']) . '")';
                break;
            }
            case 'user': {
                $sql .= ' VARCHAR(255) ';
                break;
            }
            case 'date': {
                $sql .= ' DATE ';
                break;
            }
            default: {
                break;
            }
        }
    }
    return $sql;
}

function testCreateFieldXml($FieldForm, $OldXml, $Type)
{
    $XMLString  = '';
    if(empty($OldXml))
    {
         $XMLString .= '<fieldset><fields type="' . $Type . '"><field id="' . $FieldForm['FieldName'] . '"><name>' . $FieldForm['FieldName'] . '</name><text>' . $FieldForm['FieldText'] . '</text><type>' . $FieldForm['FieldType'] . '</type><value>' . $FieldForm['FieldValue'] . '</value><status>' . $FieldForm['FieldStatus'] . '</status><option>' . $FieldForm['FieldOption'] . '</option></field></fields></fieldset>';
    }
    else
    {
        $xml = simplexml_load_string($OldXml);
        $fields = $xml->xpath('/fieldset/fields[@type="' . $Type . '"]');
        if(empty($fields))
        {
            $fields[0] = $xml->addChild('fields', '');
            $fields[0]->addAttribute('type', $Type);
        }
        $field = $xml->xpath('/fieldset/fields[@type="' . $Type . '"]/field[@id="' . $FieldForm['FieldName'] . '"]');
        if(empty($field))
        {
            $field = $fields[0]->addChild('field');
            $field->addAttribute('id', $FieldForm['FieldName']);
        }
        $field[0]->name   = $FieldForm['FieldName'];
        $field[0]->text   = $FieldForm['FieldText'];
        $field[0]->type   = $FieldForm['FieldType'];
        $field[0]->value  = $FieldForm['FieldValue'];
        $field[0]->status = $FieldForm['FieldStatus'];
        $field[0]->option = $FieldForm['FieldOption'];
        $XMLString .= $xml->asXml();
    }
    return $XMLString;
}

function testUpdateFieldStatusXml($FieldName, $OldXml, $Type, $Status)
{
    $xml = simplexml_load_string($OldXml);
    $field = $xml->xpath('/fieldset/fields[@type="' . $Type . '"]/field[@id="' . $FieldName . '"]');
    $field[0]->status = $Status;
    return $xml->asXml();
}
/*=======================================Admin Functions End===========================*/


/*===================================xajax function start =============================*/

/**
 * assign Message in ActionMessage.tpl
 *
 * @author                  Yupeng Lee<leeyupeng@gmail.com>
 * @param   object $ResponseObj   the xajaxResponse object
 * @param   string $Message       the message to play
 * @param   string $ClassName     the style of message
 */
function xAssignActionMessage(&$ResponseObj, $Message = "", $ClassName = "")
{
    if($Message == "")
    {
        return;
    }
    $ResponseObj->addAssign("ActionMessage", "style.display" , "block");
    $ResponseObj->addAssign("ActionMessage", "innerHTML", $Message);

    if($ClassName != "")
    {
        $ResponseObj->addAssign("ActionMessage", "className",  $ClassName);
    }

    $ResponseObj->addScript("shadow('ActionMessage', '{$ClassName}')");
}

/**
 * Set slave module value
 *
 * @author                 Yupeng Lee<leeyupeng@gmail.com>
 * @param   int $ProjectID
 * @return  object $objResponse  the xajaxResponse object
 */
function xSetCurrentProject($ProjectID = 0)
{
    $objResponse = new xajaxResponse();

        testSetCurrentProject($ProjectID);

    return $objResponse;
}

/**
 * Set bug selected tab
 *
 * @author                 Yupeng Lee<leeyupeng@gmail.com>
 * @param   int $TabNum
 * @return  object $objResponse  the xajaxResponse object
 */
function xSetCurrentTabNum($TabNum= 0)
{
    $objResponse = new xajaxResponse();
    testSetCurrentBugTab($TabNum);
    return $objResponse;
}



/**
 * check user login
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param   array $UserLoginForm  user login info from login form
 * @return  object $objResponse   the xajaxResponse object
 */
function xCheckUserLogin($UserLoginForm)
{
    global $_LANG, $_CFG;

    $objResponse = new xajaxResponse();
    $TestUserName = strtolower($UserLoginForm['TestUserName']);
    $TestUserPWD  = $UserLoginForm['TestUserPWD'];
    if(!sysCheckUserNameFormat($TestUserName))
    {
        xAssignActionMessage($objResponse, $_LANG['Message']['ErrorLogin'], "Error");
        $objResponse->addAssign("TestUserPWD", "value", "");
        return $objResponse;
    }
    $TestUserInfo = baseJudgeUser($TestUserName, $TestUserPWD);
    if(!$TestUserInfo)
    {
        xAssignActionMessage($objResponse, $_LANG['Message']['ErrorLogin'], "Error");
        $objResponse->addAssign("TestUserPWD", "value", "");
    }
    else
    {
        $_SESSION['TestUserACL'] = baseGetUserACL($TestUserInfo['UserName']);
        $_SESSION['TestIsAdmin'] = baseJudgeIsAdmin($TestUserInfo['UserName']);
        if(!$_SESSION['TestIsAdmin'])
        {
            $_SESSION['TestIsProjectAdmin'] = baseJudgeIsAdmin($TestUserInfo['UserName'], 'ProjectAdmin');
        }
        if(empty($_SESSION['TestUserACL']) && !$_SESSION['TestIsAdmin'])
        {
            xAssignActionMessage($objResponse, $_LANG['Message']['NoPriv'], "Warning");
        }
        else
        {
            if($UserLoginForm['RememberLoginStatus'])
            {
                $mcrypt = new Mcrypt();
                $TestUser['BFUserName'] = $TestUserInfo['UserName'];
                $TestUser['BFUserPWD']  = $TestUserPWD;
                @setcookie("BFUser", $mcrypt->encrypt(serialize($TestUser)), time()+1209600,BF_COOKIE_PATH);
                @setcookie("BFRememberStatus", '1', time()+1209600,BF_COOKIE_PATH);
            }
            else
            {
                @setcookie("BFRememberStatus", '', time()-3600,BF_COOKIE_PATH);
            }

            // register session
            $_SESSION['TestUserName'] = $TestUserInfo['UserName'];
            $_SESSION['TestRealName'] = $TestUserInfo['RealName'];
            $_SESSION['TestUserEmail'] = $TestUserInfo['Email'];
            $_SESSION['TestUserPWD'] = $TestUserPWD;

            $_SESSION['DomainTestUserName'] = $TestUserInfo['UserName'];
            $_SESSION['DomainTestUserPWD'] = $TestUserPWD;

            $_SESSION['TestUserACLSQL'] = 'ProjectID' . dbCreateIN(join(',', array_keys($_SESSION['TestUserACL'])));

            $TestCurrentProjectID = $_COOKIE['TestCurrentProjectID'] != '' && isset($_SESSION['TestUserACL'][$_COOKIE['TestCurrentProjectID']]) ? $_COOKIE['TestCurrentProjectID'] : key($_SESSION['TestUserACL']);
            testSetCurrentProject($TestCurrentProjectID);
            usleep(100);
            xAssignActionMessage($objResponse, $_LANG['Message']['SucceedLogin'], "GoodNews");

            // add user login log
            dbInsertRow('TestUserLog', "'" . mysql_real_escape_string($TestUserInfo['UserName']) . "','{$_SERVER[REMOTE_ADDR]}',now()", 'UserName,LoginIP,LoginTime');

            if($_SESSION['LoginJumpURI'] == '')
            {
                $_SESSION['LoginJumpURI'] = $_CFG["BaseURL"] . "/index.php";
            }
            $objResponse->addRedirect($_SESSION['LoginJumpURI']);
        }
    }

    return $objResponse;
}

/**
 * select user's language
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param   string $Language
 * @return  object $objResponse   the xajaxResponse object
 */
function xSelectLanguage($Language)
{
    global $_LANG, $_CFG;

    $objResponse = new xajaxResponse();
    $LangCommon = $_CFG['RealRootPath'] . '/Lang/' . $Language . '/_COMMON.php';
    if(file_exists($LangCommon))
    {
        unset($_LANG);
        require($LangCommon);
        $objResponse->addAssign('ForTestUserName', 'innerHTML', $_LANG['TestUserName']);
        $objResponse->addAssign('ForTestUserPWD', 'innerHTML', $_LANG['TestUserPWD']);
        $objResponse->addAssign('ForLanguage', 'innerHTML', $_LANG['SelectLanguage']);
        $objResponse->addAssign('ForRememberMe', 'innerHTML', $_LANG['RememberMe']);
        $objResponse->addAssign('SubmitLoginBTN', 'value', $_LANG['ButtonLogin']);
        @setcookie("BFUserLang", $Language, time()+1209600,BF_COOKIE_PATH);
    }
    return $objResponse;
}

/**
 * Add project info
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $ProjectForm       the info of form about add project.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminAddProject($ProjectForm)
{
    global $_LANG;

    $objResponse = new xajaxResponse();

    $ProjectForm['ProjectName'] = trim($ProjectForm['ProjectName']);
    /* check validity of post */
    if(empty($ProjectForm['ProjectName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoProjectName'], 'Error');
    }
    /* check wether the project's exist */
    elseif(dbGetRow('TestProject', '', "ProjectName = '{$ProjectForm[ProjectName]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['ProjectExist'], 'Warning');
    }
    /* add project */
    else
    {
        $ProjectManagers = mysql_real_escape_string($ProjectForm['ProjectManagers']);
        $ProjectGroupIDs = $ProjectForm['ProjectGroupIDs'];
        if($ProjectManagers != '') $ProjectManagers = ',' . $ProjectManagers . ',';
        if($ProjectGroupIDs != '') $ProjectGroupIDs = ',' . $ProjectGroupIDs . ',';


        $ProjectID = dbInsertRow('TestProject', "'{$ProjectForm[ProjectName]}','{$ProjectForm['DisplayOrder']}',',{$ProjectForm['NotifyEmail']},',
                                                 '{$ProjectManagers}','{$ProjectGroupIDs}',
                                                 '{$ProjectForm[ProjectDoc]}','{$ProjectForm[ProjectPlan]}',
                                                 '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now(), '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now()"
                                              , "ProjectName, DisplayOrder,NotifyEmail ,ProjectManagers, ProjectGroupIDs, ProjectDoc, ProjectPlan, AddedBy, AddDate, LastEditedBy, LastDate");
        $_SESSION['TestUserACL'][$ProjectID] = 'All';
        $_SESSION['TestUserACLSQL'] = 'ProjectID' . dbCreateIN(join(',', array_keys($_SESSION['TestUserACL'])));
        $SuccessInfo = $ProjectForm['ProjectName'] . $_LANG['SucceedAddPro'] . htmlLink($_LANG['EditProject'], 'AdminProject.php?ActionType=EditProject&ProjectID=' . $ProjectID) . "|" . htmlLink($_LANG['GoOnAddPro'], 'AdminProject.php?ActionType=AddProject') . '|' . htmlLink($_LANG['BackToProjectList'], 'AdminProjectList.php');
        $objResponse->addAppend('ProjectForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
        $objResponse->addRedirect("AdminProjectList.php", 3);
    }
    return $objResponse;
}

/**
 * update project info
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $ProjectForm       the info of form about add project.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminEditProject($ProjectForm)
{
    global $_LANG;

    $objResponse = new xajaxResponse();

    $ProjectForm['ProjectName'] = trim($ProjectForm['ProjectName']);
    /* check validity of post */
    if(empty($ProjectForm['ProjectName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoProjectName'], 'Error');
    }

    /* check wether the project's exist */
    elseif(dbGetRow('TestProject', '', "ProjectName = '{$ProjectForm[ProjectName]}' AND ProjectID <> '{$ProjectForm[ProjectID]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['ProjectExist'], 'Error');
    }

    /* edit project */
    else
    {
        $ProjectManagers = mysql_real_escape_string($ProjectForm['ProjectManagers']);
        $ProjectGroupIDs = $ProjectForm['ProjectGroupIDs'];
        if($ProjectManagers != '') $ProjectManagers = ',' . $ProjectManagers . ',';
        if($ProjectGroupIDs != '') $ProjectGroupIDs = ',' . $ProjectGroupIDs . ',';

        $ProjectInfo = dbGetRow('TestProject', '', "ProjectID = '{$ProjectForm[ProjectID]}'");
        dbUpdateRow('TestProject', 'ProjectName', "'{$ProjectForm[ProjectName]}'"
                                 , 'DisplayOrder', "'{$ProjectForm[DisplayOrder]}'"
                                 , 'NotifyEmail', "',{$ProjectForm[NotifyEmail]},'"
                                 , 'ProjectManagers', "'{$ProjectManagers}'"
                                 , 'ProjectGroupIDs', "'{$ProjectGroupIDs}'"
                                 , 'ProjectDoc', "'{$ProjectForm[ProjectDoc]}'"
                                 , 'ProjectPlan', "'{$ProjectForm[ProjectPlan]}'"
                                 , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                                 , 'LastDate', 'now()'
                                 , "ProjectID = '{$ProjectForm[ProjectID]}'");

        /* Update bug,case and result */
        dbUpdateRow('BugInfo', 'ProjectName', "'{$ProjectForm[ProjectName]}'",  "ProjectID = '{$ProjectForm[ProjectID]}'");
        dbUpdateRow('CaseInfo', 'ProjectName', "'{$ProjectForm[ProjectName]}'",  "ProjectID = '{$ProjectForm[ProjectID]}'");
        dbUpdateRow('ResultInfo', 'ProjectName', "'{$ProjectForm[ProjectName]}'",  "ProjectID = '{$ProjectForm[ProjectID]}'");

        $objResponse->addAppend('ProjectForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $_LANG['SucceedEditPro'], 'GoodNews');
        $objResponse->addRedirect("AdminProjectList.php", 3);
    }

    return $objResponse;
}

/**
 * Add Module
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $AMForm       the info of form about add module.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminAddModule($AMForm)
{
    global $_LANG;

    $objResponse = new xajaxResponse();

    $AMForm['ModuleName'] = trim($AMForm['ModuleName']);
    if(empty($AMForm['DisplayOrder']))
    {
        $AMForm['DisplayOrder'] = '0';
    }
    /* check validity of post */
    if(empty($AMForm['ModuleName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoModuleName'], 'Error');
    }
    /* check wether the module's exist */
    elseif(dbGetRow('TestModule', '', "ModuleName = '{$AMForm[ModuleName]}' AND ParentID = '{$AMForm[ParentModuleID]}' AND ModuleType='{$AMForm[ModuleType]}' AND ProjectID = '{$AMForm[ProjectID]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['ModuleExist'], 'Warning');
    }
    /* add module */
    else
    {
        if($AMForm['ParentID'] == '0')
        {
            $ModuleGrade = '1';
        }
        else
        {
            $ParentModuleInfo = testGetModuleInfo($AMForm['ParentModuleID']);
            $ModuleGrade = $ParentModuleInfo['ModuleGrade'] + 1;
        }
        /* Add slashes */
        $AMForm[AddModuleOwner] = addslashes($AMForm[AddModuleOwner]);

        $ModuleID = dbInsertRow('TestModule', "'{$AMForm[ModuleType]}','{$AMForm[ProjectID]}','{$AMForm[ModuleName]}','{$ModuleGrade}','{$AMForm[ParentModuleID]}','{$AMForm[AddModuleOwner]}', '{$AMForm[DisplayOrder]}', now(),now()"
                                              , "ModuleType,ProjectID, ModuleName, ModuleGrade, ParentID, ModuleOwner, DisplayOrder, AddDate, LastDate");
        dbUpdateRow('TestProject', 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'", 'LastDate', 'now()', "ProjectID = '{$AMForm[ProjectID]}'");
        $SuccessInfo = $_LANG['SucceedAddModule'];
        $objResponse->addScript("setTimeout('window.location.reload()',2000);");
        xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
    }
    return $objResponse;
}

/**
 * Edit Module
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $EMForm       the info of form about edit module.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminEditModule($EMForm)
{
    global $_LANG;

    $objResponse = new xajaxResponse();

    $objResponse->addScript("xajax.$('SaveModuleSubmit').disabled='';");
    $EMForm['ModuleName'] = trim($EMForm['ModuleName']);
    if(empty($EMForm['DisplayOrder']))
    {
        $EMForm['DisplayOrder'] = '0';
    }
    /* check validity of post */
    if(empty($EMForm['ModuleName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoModuleName'], 'Error');
    }
    /* check wether the module's exist */
    elseif(dbGetRow('TestModule', '', "ModuleName = '{$EMForm[ModuleName]}' AND ParentID = '{$EMForm[ParentModuleID]}' AND ModuleType='{$EMForm[ModuleType]}' AND ModuleID <> '{$EMForm[ModuleID]}' AND ProjectID = '{$EMForm[ProjectID]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['ModuleExist'], 'Warning');
    }
    elseif($EMForm['ParentModuleID'] == $EMForm['ModuleID'])
    {
        xAssignActionMessage($objResponse, $_LANG['ModuleNotBeRecursive'], 'Warning');
    }
    else
    {
        if($EMForm['DeleteModule'] == '1')
        {
            $ParentModulePath = testGetModulePath($EMForm[ParentModuleID]);
            if(dbGetRow('TestModule','', "ParentID = $EMForm[ModuleID]"))
            {
                xAssignActionMessage($objResponse, $_LANG['ModuleHasChildModule'], 'Warning');
            }
            else
            {
                if($EMForm[ModuleType] == 'Bug')
                {
                    dbUpdateRow('BugInfo','ModuleID', $EMForm['ParentModuleID'], 'ModulePath', "'{$ParentModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");
                }
                else
                {
                    dbUpdateRow('CaseInfo','ModuleID', $EMForm['ParentModuleID'], 'ModulePath', "'{$ParentModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");
                    dbUpdateRow('ResultInfo','ModuleID', $EMForm['ParentModuleID'],'ModulePath', "'{$ParentModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");
                }
                dbDeleteRow('TestModule',"ModuleID = {$EMForm[ModuleID]}");
                $SuccessInfo = $_LANG['SucceedDeleteModule'];
                $objResponse->addRedirect("AdminModuleList.php?ProjectID={$EMForm[ProjectID]}&ModuleType={$EMForm[ModuleType]}&ModuleID={$EMForm[ParentModuleID]}", 2);
                xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
            }
        }
        else
        {
            if(empty($EMForm[ModuleID]))
            {
                if($EMForm['ProjectID'] == $EMForm['RawProjectID'])
                {
                    xAssignActionMessage($objResponse, $_LANG['MergeSelfDenied'], 'Error');
                }
                else
                {
                    if($EMForm['ParentModuleID'] == '0')
                    {
                        $ModuleGrade = '1';
                    }
                    else
                    {
                        $ParentModuleInfo = testGetModuleInfo($EMForm['ParentModuleID']);
                        $ModuleGrade = $ParentModuleInfo['ModuleGrade'] + 1;
                    }

                    /* Add slashes */
                    $EMForm[EditModuleOwner] = addslashes($EMForm[EditModuleOwner]);

                    // add a new module
                    $ModuleID = dbInsertRow('TestModule', "'{$EMForm[ModuleType]}','{$EMForm[ProjectID]}','{$EMForm[ModuleName]}','{$ModuleGrade}','{$EMForm[ParentModuleID]}','{$EMForm[EditModuleOwner]}', '{$EMForm[DisplayOrder]}', now(),now()"
                                                  , "ModuleType,ProjectID, ModuleName, ModuleGrade, ParentID, ModuleOwner, DisplayOrder, AddDate, LastDate");

                    $ProjectModuleList = testGetModuleList($EMForm['RawProjectID'], $EMForm[ModuleType]);
                    $ChildModuleIDList = array_keys($ProjectModuleList);


                    /* Update bug,case and result */
                    $ModulePath = testGetModulePath($ModuleID);
                    $ProjectInfo = testGetProjectList("ProjectID = '{$EMForm[ProjectID]}'");
                    $ProjectName = $ProjectInfo[$EMForm['ProjectID']]['ProjectName'];
                    dbUpdateRow('BugInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID", $ModuleID, "ProjectID = '{$EMForm[RawProjectID]}' AND ModuleID = 0");
                    dbUpdateRow('CaseInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID", $ModuleID, "ProjectID = '{$EMForm[RawProjectID]}' AND ModuleID = 0");
                    dbUpdateRow('ResultInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID", $ModuleID, "ProjectID = '{$EMForm[RawProjectID]}' AND ModuleID = 0");

                    /* Update Child's ModuleGrade */
                    dbUpdateRow('TestModule', 'ParentID',$ModuleID, "ModuleType = '{$EMForm[ModuleType]}' AND ParentID = 0 AND ProjectID = {$EMForm['RawProjectID']}");
                    dbUpdateRow('TestModule', 'ModuleGrade',"ModuleGrade + {$ModuleGrade} + 1", 'ProjectID', "'{$EMForm[ProjectID]}'",  "ModuleType = '{$EMForm[ModuleType]}' AND ProjectID = {$EMForm['RawProjectID']}");
                    foreach($ChildModuleIDList as $ChildModuleID)
                    {
                        $ModulePath = testGetModulePath($ChildModuleID);
                        dbUpdateRow('BugInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                        dbUpdateRow('CaseInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                        dbUpdateRow('ResultInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                    }

                    $SuccessInfo = $_LANG['SucceedMergeProject'];
                    $objResponse->addScript("setTimeout('window.location.reload()',2000);");
                    xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
                }

            }
            else
            {
                $RawModuleInfo = testGetModuleInfo($EMForm[ModuleID]);
                $RawProjectID = $RawModuleInfo['ProjectID'];
                $ProjectModuleList = testGetProjectModuleList($RawProjectID, $EMForm[ModuleType]);
                $ChildModuleIDList = explode(',', $ProjectModuleList[$EMForm[ModuleID]]['ChildIDs']);
                if(in_array($EMForm['ParentModuleID'], $ChildModuleIDList))
                {
                    xAssignActionMessage($objResponse, $_LANG['ModuleNotBeRecursive'], 'Warning');
                }
                else
                {
                    if($EMForm['ParentModuleID'] == '0')
                    {
                        $ModuleGrade = '1';
                    }
                    else
                    {
                        $ParentModuleInfo = testGetModuleInfo($EMForm['ParentModuleID']);
                        $ModuleGrade = $ParentModuleInfo['ModuleGrade'] + 1;
                    }

                    /* Add slashes */
                    $EMForm[EditModuleOwner] = addslashes($EMForm[EditModuleOwner]);

                    dbUpdateRow('TestModule', 'ModuleType', "'{$EMForm[ModuleType]}'", 'ProjectID', "'{$EMForm[ProjectID]}'", 'ModuleName', "'{$EMForm[ModuleName]}'",
                                              'ModuleGrade', "'{$ModuleGrade}'", 'ParentID', "'{$EMForm[ParentModuleID]}'",
                                              'ModuleOwner', "'{$EMForm[EditModuleOwner]}'", 'LastDate', "now()",
                                              'DisplayOrder', "'{$EMForm['DisplayOrder']}'",
                                              "ModuleID = '{$EMForm[ModuleID]}'");
                    /* Update bug,case and result */
                    $ModulePath = testGetModulePath($EMForm[ModuleID]);
                    $ProjectInfo = testGetProjectList("ProjectID = '{$EMForm[ProjectID]}'");
                    $ProjectName = $ProjectInfo[$EMForm['ProjectID']]['ProjectName'];
                    dbUpdateRow('BugInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");
                    dbUpdateRow('CaseInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");
                    dbUpdateRow('ResultInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$EMForm[ModuleID]}'");

                    /* Update Child's ModuleGrade */
                    $ParentID = $EMForm[ModuleID];
                    $ProjectModuleList[$EMForm[ModuleID]]['ModuleGrade'] = $ModuleGrade;
                    array_shift($ChildModuleIDList);
                    foreach($ChildModuleIDList as $ChildModuleID)
                    {
                        $ParentID = $ProjectModuleList[$ChildModuleID]['ParentID'];
                        $ChildModuleGrade = $ProjectModuleList[$ParentID]['ModuleGrade']+1;
                        $ProjectModuleList[$ChildModuleID]['ModuleGrade'] = $ChildModuleGrade;
                        dbUpdateRow('TestModule', 'ModuleGrade',$ChildModuleGrade, 'ProjectID', "'{$EMForm[ProjectID]}'",  "ModuleID = {$ChildModuleID}");
                        $ModulePath = testGetModulePath($ChildModuleID);
                        dbUpdateRow('BugInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                        dbUpdateRow('CaseInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                        dbUpdateRow('ResultInfo', 'ProjectID', "'{$EMForm[ProjectID]}'", 'ProjectName', "'{$ProjectName}'", 'ModulePath', "'{$ModulePath}'", "ModuleID = '{$ChildModuleID}'");
                    }

                    $SuccessInfo = $_LANG['SucceedEditModule'];
                    $objResponse->addScript("setTimeout('window.location.reload()',2000);");
                    xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
                }
            }
        }
        dbUpdateRow('TestProject', 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'", 'LastDate', 'now()', "ProjectID = '{$EMForm[ProjectID]}'");
    }
    return $objResponse;
}


/**
 * Add user info
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $UserForm       the info of form about add user.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminAddUser($UserForm)
{
    global $_LANG, $_CFG;

		Rainy_Debug($UserForm,__FUNCTION__,__LINE__,__FILE__);

    $objResponse = new xajaxResponse();
		
		//Pre-Handler for PostUserInfo
		PostUserInfoPreHandler2($UserForm);      
    $UserForm['UserName'] = mysql_real_escape_string(strtolower(htmlspecialchars(trim($UserForm['UserName']))));
    $UserForm['RealName'] = htmlspecialchars(trim($UserForm['RealName']));
    $UserForm['Email'] = trim($UserForm['Email']);
    Rainy_Debug($UserForm,__FUNCTION__,__LINE__,__FILE__);


    /* check validity of post */
    $ErrorMsg = array();
    if(empty($UserForm['UserName']))
    {
        $ErrorMsg[] = $_LANG['NoUserName'];
    }
    elseif(!sysCheckUserNameFormat($UserForm['UserName']))
    {
        $ErrorMsg[] = $_LANG['InvalidUserName'];
    }

    if($UserForm['AuthMode'] == 'LDAP')
    {
        if(!preg_match("/^[_\.0-9a-z-]+\\\\[_\.0-9a-z-]+$/i", sysStripSlash($UserForm['UserName'])))
        {
            $ErrorMsg[] = $_LANG['InvalidLDAPUserNameFormat'];
        }
        else
        {
            $TestUserInfo = ldapJudgeUser($_SESSION['DomainTestUserName'],$_SESSION['DomainTestUserPWD']);
            if(empty($TestUserInfo))
            {
                if(empty($_SERVER["PHP_AUTH_USER"]) || empty($_SERVER["PHP_AUTH_PW"]))
                {
                    header ( "WWW-Authenticate: Basic realm=\"\"");
                    header('HTTP/1.0 401 Unauthorized');
                    return $objResponse;
                }
                else
                {
                    $_SESSION['DomainTestUserName'] = $_SERVER["PHP_AUTH_USER"];
                    $_SESSION['DomainTestUserPWD'] = $_SERVER["PHP_AUTH_PW"];
                    $TestUserInfo = ldapJudgeUser($_SESSION['DomainTestUserName'],$_SESSION['DomainTestUserPWD']);
                }
            }
            if(empty($TestUserInfo))
            {
                header ( "WWW-Authenticate: Basic realm=\"\"");
                header('HTTP/1.0 401 Unauthorized');
                return $objResponse;
            }
            else
            {
                $TestUserInfo = ldapJudgeUser($_SESSION['DomainTestUserName'],$_SESSION['DomainTestUserPWD'],$UserForm['UserName']);
                if(empty($TestUserInfo))
                {
                    $ErrorMsg[] = $_LANG['LDAPUserNotFound'];
                }
                else
                {
                    $UserForm['RealName'] = $TestUserInfo['RealName'];
                    $UserForm['Email'] = $TestUserInfo['Email'];
                    $UserForm['UserPassword'] = baseEncryptUserPWD(time());
                }
            }
        }
    }
    else
    {
        if(empty($UserForm['RealName']))
        {
            $ErrorMsg[] = $_LANG['NoRealName'];
        }
        if($UserForm['UserPassword'] == '')
        {
            $ErrorMsg[] = $_LANG['NoPassword'];
        }
        else
        {
            $UserForm['UserPassword'] = baseEncryptUserPWD($UserForm['UserPassword']);
        }
        if(empty($UserForm['Email']))
        {
            $ErrorMsg[] = $_LANG['NoEmail'];
        }
        elseif(!sysCheckEmailFormat($UserForm['Email']))
        {
            $ErrorMsg[] = $_LANG['InvalidEmail'];
        }
    }

    if(!empty($ErrorMsg))
    {
        xAssignActionMessage($objResponse, join('<br />', $ErrorMsg), 'Error');
    }
     /* check wether the user's exist */
    elseif(dbGetRow($_CFG['UserTable']['TableName'], '', "UserName = '{$UserForm[UserName]}'"))
    {
    		Rainy_Debug("UserExist: UserName [" . $UserForm['UserName'] . "]",__FUNCTION__,__LINE__,__FILE__,1);
        xAssignActionMessage($objResponse, $_LANG['UserExist'], 'Warning');
    }
    else
    {
        $UserID = dbInsertRow($_CFG['UserTable']['TableName'], "'{$UserForm[UserName]}','{$UserForm[RealName]}','{$UserForm[UserPassword]}', '{$UserForm[Email]}', '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now(), '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now(), '0', '{$UserForm[AuthMode]}'"
            , "UserName, RealName, UserPassword, Email, AddedBy, AddDate, LastEditedBy, LastDate, IsDroped, AuthMode");
				
				//SendOpenUserNotifyMail
				SendOpenUserNotifyMail($UserForm,$UserID);
				
				if($UserForm['AuthMode'] == 'LDAP')
        {
            $SuccessInfo = sysStripSlash($UserForm['UserName']) . ' ' . $_LANG['SucceedAddUser'] . "|" . htmlLink($_LANG['GoOnAddUser'], 'AdminUser.php?ActionType=AddUser') . '|' . htmlLink($_LANG['BackToUserList'], 'AdminUserList.php');
        }
        else
        {
            $SuccessInfo = sysStripSlash($UserForm['UserName']) . ' ' . $_LANG['SucceedAddUser'] . htmlLink($_LANG['EditUser'], 'AdminUser.php?ActionType=EditUser&UserID=' . $UserID) . "|" . htmlLink($_LANG['GoOnAddUser'], 'AdminUser.php?ActionType=AddUser') . '|' . htmlLink($_LANG['BackToUserList'], 'AdminUserList.php');
        }
        $objResponse->addAppend('UserForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
        $objResponse->addRedirect("AdminUserList.php", 3);
    }
    return $objResponse;
}

/**
 * Edit user info
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $UserForm       the info of form about edit user.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminEditUser($UserForm)
{
    global $_LANG, $_CFG;
        
    $objResponse = new xajaxResponse();
		Rainy_Debug($UserForm,__FUNCTION__,__LINE__,__FILE__);
    
    //Pre-Handler for PostUserInfo
		PostUserInfoPreHandler2($UserForm);   
    $UserForm['UserName'] = strtolower(htmlspecialchars(trim($UserForm['UserName'])));
    $UserForm['RealName'] = htmlspecialchars(trim($UserForm['RealName']));
    $UserForm['Email'] = trim($UserForm['Email']);
		Rainy_Debug($UserForm,__FUNCTION__,__LINE__,__FILE__);

    /* check validity of post */
    $ErrorMsg = array();
    if(empty($UserForm['RealName']))
    {
        $ErrorMsg[] = $_LANG['NoRealName'];
    }
    if(empty($UserForm['Email']))
    {
        $ErrorMsg[] = $_LANG['NoEmail'];
    }
    elseif(!preg_match("/^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4}$/i", $UserForm['Email']))
    {
        $ErrorMsg[] = $_LANG['InvalidEmail'];
    }
    if(!empty($ErrorMsg))
    {
        xAssignActionMessage($objResponse, join('<br />', $ErrorMsg), 'Error');
    }
    /* edit user */
    else
    {
        $UserInfo = dbGetRow($_CFG['UserTable']['TableName'], '', "UserID = '{$UserForm[UserID]}'");
        $DiffArray = sysArrayDiffAssoc($UserInfo, $UserForm, 'UserID,UserName,UserPassword,RealName,Email');

        if(empty($DiffArray) && $UserForm['UserPassword'] == '')
        {
            xAssignActionMessage($objResponse, $_LANG['NoEditUser'], 'Warning');
        }
        else
        {
            if($UserForm['UserPassword'] == '')
            {
                $UserForm['UserPassword'] = $UserInfo['UserPassword'];
            }
            else
            {
                $UserForm['UserPassword'] = baseEncryptUserPWD($UserForm['UserPassword']);
            }
           dbUpdateRow($_CFG['UserTable']['TableName'], 'RealName', "'{$UserForm[RealName]}'"
                                                       , 'UserPassword', "'{$UserForm[UserPassword]}'"
                                                       , 'Email', "'{$UserForm[Email]}'"
                                                       , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) ."'"
                                                       , 'LastDate', 'now()'
                                                       , "UserID = '{$UserForm[UserID]}'");
     				//Send Notify Email
						SendEditUserNotifyMail($UserForm['UserID'],$UserForm,$UserInfo,$DiffArray);
            
            $objResponse->addAppend('UserForm', 'style.display', 'none');
            xAssignActionMessage($objResponse, $_LANG['SucceedEditUser'], 'GoodNews');
            $objResponse->addRedirect("AdminUserList.php", 3);
        }
    }
    return $objResponse;
}

/**
 * Add Group
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $GroupForm       the info of form about add group.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminAddGroup($GroupForm)
{
    global $_LANG, $_CFG;

    $objResponse = new xajaxResponse();

    $GroupForm['GroupName'] = trim($GroupForm['GroupName']);
    /* check validity of post */
    if(empty($GroupForm['GroupName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoGroupName'], 'Error');
    }
    /* check wether the group's exist */
    elseif(dbGetRow('TestGroup', '', "GroupName = '{$GroupForm[GroupName]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['GroupNameExist'], 'Warning');
    }
    /* add group */
    else
    {
        $GroupUser = mysql_real_escape_string($GroupForm['GroupUserNames']);
        $GroupACL = NULL;
        if($GroupUser != '')
        {
            $GroupUserList = testGetUserList($_CFG['UserTable']['UserName'] . dbCreateIN($GroupUser));
            uasort($GroupUserList, 'testCmpPreAppendName');
            $GroupUser = join(',',array_keys($GroupUserList));

            /* Add "," at both end of the variable finally like this: ,wwccss,admin, */
            $GroupUser = mysql_real_escape_string(',' . $GroupUser . ',');
        }

        $GroupManager = mysql_real_escape_string($GroupForm['GroupManagerNames']);
        if($GroupManager != '')
        {
            $GroupManagerList = testGetUserList($_CFG['UserTable']['UserName'] . dbCreateIN($GroupManager));
            uasort($GroupManagerList, 'testCmpPreAppendName');
            $GroupManager = join(',',array_keys($GroupManagerList));

            /* Add "," at both end of the variable finally like this: ,wwccss,admin, */
            $GroupManager = mysql_real_escape_string(',' . $GroupManager . ',');
        }

        $GroupID = dbInsertRow('TestGroup', "'{$GroupForm[GroupName]}','{$GroupManager}','{$GroupUser}', '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now(), '" . mysql_real_escape_string($_SESSION['TestUserName']) . "', now()"
                                              , "GroupName, GroupManagers, GroupUser, AddedBy, AddDate, LastEditedBy, LastDate");
        $SuccessInfo = $GroupForm['GroupName'] . $_LANG['SucceedAddGroup'] . htmlLink($_LANG['EditGroup'], 'AdminGroup.php?ActionType=EditGroup&GroupID=' . $GroupID) . "|" . htmlLink($_LANG['GoOnAddGroup'], 'AdminGroup.php?ActionType=AddGroup') . '|' . htmlLink($_LANG['BackToGroupList'], 'AdminGroupList.php');
        $objResponse->addAppend('GroupForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
        $objResponse->addRedirect("AdminGroupList.php", 3);
    }
    return $objResponse;
}

/**
 * Edit Group
 *
 * @author                        Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $GroupForm       the info of form about Edit group.
 * @return   object $objResponse  the xajaxResponse object
 */
function xAdminEditGroup($GroupForm)
{
    global $_LANG, $_CFG;

    $objResponse = new xajaxResponse();

    $GroupForm['GroupName'] = trim($GroupForm['GroupName']);
    /* check validity of post */
    if(empty($GroupForm['GroupName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoGroupName'], 'Error');
    }
    /* check wether the group's exist */
    elseif(dbGetRow('TestGroup', '', "GroupName = '{$GroupForm[GroupName]}' AND GroupID <> '{$GroupForm[GroupID]}'"))
    {
        xAssignActionMessage($objResponse, $_LANG['GroupNameExist'], 'Warning');
    }
    /* edit group */
    else
    {
        $GroupUser = mysql_real_escape_string($GroupForm['GroupUserNames']);
        $GroupACL = NULL;
        if($GroupUser != '')
        {
            $GroupUserList = testGetUserList($_CFG['UserTable']['UserName'] .  dbCreateIN($GroupUser));
            uasort($GroupUserList, 'testCmpPreAppendName');
            $GroupUser = mysql_real_escape_string(join(',',array_keys($GroupUserList)));

            /* Edit "," at both end of the variable finally like this: ,wwccss,admin, */
            $GroupUser = ',' . $GroupUser . ',';
        }
        $GroupManager = mysql_real_escape_string($GroupForm['GroupManagerNames']);
        if($GroupManager != '')
        {
            $GroupManagerList = testGetUserList($_CFG['UserTable']['UserName'] . dbCreateIN($GroupManager));
            uasort($GroupManagerList, 'testCmpPreAppendName');
            $GroupManager = mysql_real_escape_string(join(',',array_keys($GroupManagerList)));

            /* Add "," at both end of the variable finally like this: ,wwccss,admin, */
            $GroupManager = ',' . $GroupManager . ',';
        }
        dbUpdateRow('TestGroup', 'GroupName', "'{$GroupForm[GroupName]}'", 'GroupManagers', "'{$GroupManager}'", 'GroupUser', "'{$GroupUser}'"
                                   , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'", 'LastDate', 'now()'
                                   , "GroupID ='{$GroupForm[GroupID]}'");
        $SuccessInfo = $GroupForm['GroupName'] . $_LANG['SucceedEditGroup'];
        $objResponse->addAppend('GroupForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $SuccessInfo, 'GoodNews');
        $objResponse->addRedirect("AdminGroupList.php", 3);
    }
    return $objResponse;
}

function xShowAndHidden($BoldID, $NormalID, $ShowIDs, $HiddenIDs)
{
    $objResponse = new xajaxResponse();
    $ShowIDs = explode(',', $ShowIDs);
    foreach($ShowIDs as $id)
    {
        $objResponse->addAssign($id, "style.display", "block");
    }
    $HiddenIDs = explode(',', $HiddenIDs);
    foreach($HiddenIDs as $id)
    {
        $objResponse->addAssign($id, "style.display", "none");
    }
    $objResponse->addAssign($BoldID, "style.fontWeight","bold");
    $objResponse->addAssign($NormalID, "style.fontWeight","normal");
    return $objResponse;
}

function xAdminAddField($Type, $ProjectID, $FieldForm)
{
    global $_LANG;
    $objResponse = new xajaxResponse();
    $ProjectInfo = dbGetRow('TestProject', null, 'ProjectID = ' . $ProjectID);
    $tableName = testGetFieldTable($Type, $ProjectID);
    $flag = true;
    if(empty($ProjectInfo))
    {
        xAssignActionMessage($objResponse, $_LANG['NoProject'], 'Error');
        $flag = false;
    }
    else if(empty($Type))
    {
        xAssignActionMessage($objResponse, $_LANG['NoType'], 'Error');
        $flag = false;
    }
    else if(empty($FieldForm['FieldText']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoFieldText'], 'Error');
        $flag = false;
    }
    else if(empty($FieldForm['FieldName']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoFieldName'], 'Error');
        $flag = false;
    }
    else if(strlen($FieldForm['FieldText']) < 4 || strlen($FieldForm['FieldText']) > 32)
    {
        xAssignActionMessage($objResponse, $_LANG['FieldTextNotValid'], 'Error');
        $flag = false;
    }
    else if(!preg_match('|^[a-zA-Z]{4,16}$|', $FieldForm['FieldName']))
    {
        xAssignActionMessage($objResponse, $_LANG['FieldNameNotValid'], 'Error');
        $flag = false;
    }
    else if(dbCheckFieldExist($tableName, $FieldForm['FieldName']))
    {
        xAssignActionMessage($objResponse, $_LANG['FieldNameRepeat'], 'Error');
        $flag = false;
    }
    else if(dbCheckFieldExist(dbGetPrefixTableNames($Type.'Info'), $FieldForm['FieldName']))
    {
        xAssignActionMessage($objResponse, $_LANG['FieldNameRepeatWithBasic'], 'Error');
        $flag = false;
    }
    else if(in_array(strtolower($FieldForm['FieldName']), $_LANG['MySQL']['Keywords']))
    {
        xAssignActionMessage($objResponse, $_LANG['MySQL']['Warning'], 'Error');
        $flag = false;
    }
    else if($FieldForm['FieldType'] == 'mulit')
    {
        $arr = explode(',', $FieldForm['FieldValue']);
        if(count($arr) != count(array_unique($arr)))
        {
            xAssignActionMessage($objResponse, $_LANG['MulitSelectUniqueValue'], 'Error');
            $flag = false;
        }
    }

    if($flag)
    {
        $sql = testGetFieldSql($FieldForm);
        if(!dbCheckTableExists($tableName))
        {
            $sql = 'FieldID INT(11) PRIMARY KEY,' . $sql;
            dbCreateTable($tableName, $sql);
        }
        else
        {
            dbAlterTable($tableName, $sql);
        }

        $xml = testCreateFieldXml($FieldForm, $ProjectInfo['FieldSet'], $Type);
        dbUpdateRow('TestProject', 'FieldSet', "'{$xml}'"
                                 , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                                 , 'LastDate', 'now()'
                                 , "ProjectID = '{$ProjectID}'");
        xAssignActionMessage($objResponse, $_LANG['SucceedAddField'], 'GoodNews');
        $objResponse->addAppend('FieldForm', 'style.display', 'none');
        $objResponse->addScript("setInterval(\"location.href='AdminModuleList.php?ProjectID=$ProjectID&ModuleType=$Type&ShowField=true';\", 3000)");
    }
    return $objResponse;
}

function xAdminUpdateField($Type, $ProjectID, $FieldForm)
{
    global $_LANG;
    $objResponse = new xajaxResponse();
    $ProjectInfo = dbGetRow('TestProject', null, 'ProjectID = ' . $ProjectID);
    $flag = true;
    if(empty($ProjectInfo))
    {
        xAssignActionMessage($objResponse, $_LANG['NoProject'], 'Error');
        $flag = false;
    }
    else if(empty($Type))
    {
        xAssignActionMessage($objResponse, $_LANG['NoType'], 'Error');
        $flag = false;
    }
    else if(empty($FieldForm['FieldText']))
    {
        xAssignActionMessage($objResponse, $_LANG['NoFieldText'], 'Error');
        $flag = false;
    }
    else if(strlen($FieldForm['FieldText']) < 4 || strlen($FieldForm['FieldText']) > 32)
    {
        xAssignActionMessage($objResponse, $_LANG['FieldTextNotValid'], 'Error');
        $flag = false;
    }
    else if($FieldForm['FieldType'] == 'mulit')
    {
        $arr = explode(',', $FieldForm['FieldValue']);
        if(count($arr) != count(array_unique($arr)))
        {
            xAssignActionMessage($objResponse, $_LANG['MulitSelectUniqueValue'], 'Error');
            $flag = false;
        }
    }

    if($flag)
    {
        $tableName = testGetFieldTable($Type, $ProjectID);
        $sql = $FieldForm['FieldOldName'] . ' '. testGetFieldSql($FieldForm);
        dbAlterField($tableName, $sql);
        $ProjectInfo = dbGetRow('TestProject', null, 'ProjectID = ' . $ProjectID);
        $xml = testCreateFieldXml($FieldForm, $ProjectInfo['FieldSet'], $Type);
        dbUpdateRow('TestProject', 'FieldSet', "'{$xml}'"
                                 , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                                 , 'LastDate', 'now()'
                                 , "ProjectID = '{$ProjectID}'");
        $objResponse->addAppend('FieldForm', 'style.display', 'none');
        xAssignActionMessage($objResponse, $_LANG['SucceedUpdateField'], 'GoodNews');
        $objResponse->addScript("setInterval(\"location.href='AdminModuleList.php?ProjectID=$ProjectID&ModuleType=$Type&ShowField=true';\", 3000)");
    }
    return $objResponse;
}

function xUpdateFieldStatus($Type, $ProjectID, $FieldName, $Status)
{
    $objResponse = new xajaxResponse();
    $tableName = testGetFieldTable($Type, $ProjectID);
    $ProjectInfo = dbGetRow('TestProject', null, 'ProjectID = ' . $ProjectID);
    $xml = testUpdateFieldStatusXml($FieldName, $ProjectInfo['FieldSet'], $Type, $Status);
    dbUpdateRow('TestProject', 'FieldSet', "'{$xml}'"
                    , 'LastEditedBy', "'" . mysql_real_escape_string($_SESSION['TestUserName']) . "'"
                    , 'LastDate', 'now()'
                    , "ProjectID = '{$ProjectID}'");
    $objResponse->addScript("location.href='AdminModuleList.php?ProjectID=$ProjectID&ModuleType=$Type&ShowField=true';");
    return $objResponse;
}

function xAddField($Type, $ProjectID)
{
    $objResponse = new xajaxResponse();
    $objResponse->addScript("location.href='AdminField.php?ProjectID=$ProjectID&ModuleType=$Type&Action=AddField';");
    return $objResponse;
}

/**
 * Set slave module value
 *
 * @author                            Yupeng Lee<leeyupeng@gmail.com>
 * @param    int    $ProjectID
 * @param    string $ModuleListSpanID
 * @param    string $ModuleListName
 * @param    string $ModuleType        Bug or Case
 * @return   object $objResponse       the xajaxResponse object
 */
function xProjectSetSlaveModule($ProjectID, $ModuleListSpanID, $ModuleListName = 'MoudleID', $ModuleType = 'Bug')
{
    $objResponse = new xajaxResponse();

    $OnChangeStr = 'onchange="';
    $OnChangeStr .= 'xajax_xSetModuleOwner(this.value);"';
    $OnChangeStr .= ' class="MyInput RequiredField"';
    $ModuleSelectList = testGetSelectModuleList($ProjectID, $ModuleListName, $_SESSION['TestCurrentModuleID'], $OnChangeStr, $ModuleType);

    $objResponse->addAssign($ModuleListSpanID, 'innerHTML', $ModuleSelectList);

    return $objResponse;
}

/**
 * Set slave module value
 *
 * @author                                Yupeng Lee<leeyupeng@gmail.com>
 * @param    int    $ProjectID
 * @param    string $UserListSpanID
 * @param    string $AssignedUserListName
 * @return   object $objResponse          the xajaxResponse object
 */
function xProjectSetAssignedUser($ProjectID, $UserListSpanID='AssignedToUserList', $AssignedUserListName = 'AssignedTo')
{
    $objResponse = new xajaxResponse();
    $ProjectUserList = testGetProjectUserList($ProjectID, true);
    $ProjectUserList += array('Closed' => 'Closed');
    $SelectAssignUserList = htmlSelect($ProjectUserList, $AssignedUserListName, '','', 'class="NormalSelect MyInput RequiredField"');
    $objResponse->addAssign($UserListSpanID, 'innerHTML', $SelectAssignUserList);
    $objResponse->addAssign('CurrentProjectID', 'value', $ProjectID);
    $objResponse->addClear('MailTo', 'selectDiv');
    return $objResponse;
}

/**
 * Set slave module value
 *
 * @author                                Yupeng Lee<leeyupeng@gmail.com>
 * @param    int    $ProjectID
 * @param    string $UserListSpanID
 * @param    string $AssignedUserListName
 * @return   object $objResponse          the xajaxResponse object
 */
function xProjectSetScriptedBy($ProjectID, $UserListSpanID='ScriptedByList', $AssignedUserListName = 'ScriptedBy')
{
    $objResponse = new xajaxResponse();
    $ProjectUserList = testGetProjectUserList($ProjectID, true);
    unset($ProjectUserList['Active']);
    $ProjectUserList = array(''=>'')+$ProjectUserList;
    $SelectAssignUserList = htmlSelect($ProjectUserList, $AssignedUserListName, '','', 'class="NormalSelect MyInput"');
    $objResponse->addAssign($UserListSpanID, 'innerHTML', $SelectAssignUserList);
    return $objResponse;
}

/**
 * Set search condition
 *
 * @author                       xiaowen zhao<youzhao.zxw@taobao.com>
 * @param    int    $ConditionNum
 * @return   object $objResponse the xajaxResponse object
 */
function getSearchCondition($QueryType)
{
    $ConditionNum = "NUM_TEMPLATE";
    global $_LANG;
    $LeftParenthesesName = 'LeftParenthesesName';
    $RightParenthesesName = 'RightParenthesesName';
    $FieldName = 'Field';
    $OperatorName = 'Operator';
    $ValueName = 'Value';
    $AndOrName = 'AndOr';
    $Attrib = 'class="FullSelect"';
    $FieldListOnChange = ' onchange="setQueryForm(' . $ConditionNum . ');"';
    $OperatorListOnChange = ' onchange="setQueryValue(' . $ConditionNum . ');"';
    $FieldList = htmlSelect($_LANG[$QueryType.'QueryField'], $FieldName . $ConditionNum, $Mode, 'OpenedBy', $Attrib . $FieldListOnChange);
    $OperatorList = htmlSelect($_LANG['Operators'], $OperatorName . $ConditionNum, $Mode, '=', $Attrib . $OperatorListOnChange);

    $ValueList = '<input id="' . $ValueName . $ConditionNum . '" name="' . $ValueName . $ConditionNum . '" type="text" size="5" style="width:95%;"/>';
    $AndOrList = htmlSelect($_LANG['AndOr'], $AndOrName . $ConditionNum, $Mode, '', $Attrib);
    $LeftParentheses = htmlSelect($_LANG['LeftParentheses'], $LeftParenthesesName . $ConditionNum, $Mode, '', $Attrib." onchange=\"validateParentheses()\"");
    $RightParentheses = htmlSelect($_LANG['RightParentheses'], $RightParenthesesName . $ConditionNum, $Mode, '', $Attrib." onchange=\"validateParentheses()\"");
    $AddRemoveLink = '<a href="javascript:;" onclick="addSearchField('.$ConditionNum.');return false;" ><img src="Image/add_search.gif"/></a>&nbsp;&nbsp;<a href="javascript:;" onclick="removeSearchField('.$ConditionNum.');return false;"><img src="Image/cancel_search.gif"/></a>';
    $ConditionDetail = '<tr id="SearchConditionRow'.$ConditionNum.'" ><td>'.$LeftParentheses .'</td><td>'.$FieldList.'</td>
        <td>'.$OperatorList.'</td><td id="ValueTd'.$ConditionNum.'">'.$ValueList.'</td>
            <td>'.$RightParentheses.'</td><td>'.$AndOrList.'</td><td>'.$AddRemoveLink.'</td></tr>';
    $ConditionDetail = str_replace('"', '\"', $ConditionDetail);
    $ConditionDetail = str_replace(array("\r\n", "\r", "\n"), "",$ConditionDetail);
    return $ConditionDetail;
}
/**
 * Set module owner to assigned user
 *
 * @author                       Yupeng Lee<leeyupeng@gmail.com>
 * @param    int    $ModuleID
 * @param    string $AssignedTo
 * @return   object $objResponse the xajaxResponse object
 */
function xSetModuleOwner($ModuleID, $AssignedToID = 'AssignedTo')
{
    $objResponse = new xajaxResponse();

    $ModuleInfo = testGetModuleInfo($ModuleID);
    $ModuleOwner = $ModuleInfo['ModuleOwner'];
    if($ModuleOwner == '')
    {
        $ModuleOwner = 'Active';
    }

    $objResponse->addScript("selectOneItem(xajax.$('{$AssignedToID}'), '{$ModuleOwner}');");

    return $objResponse;
}

/**
 * Delete file
 *
 * @author                       Yupeng Lee<leeyupeng@gmail.com>
 * @param     string   $FileID
 * @return   object $objResponse the xajaxResponse object
 */
function xDeleteTestFile($FileID)
{
    $objResponse = new xajaxResponse();

    dbUpdateRow('TestFile', 'IsDroped', "'1'" , "FileID = '{$FileID}'");
    $objResponse->addRemove('TestFile' . $FileID);
    return $objResponse;
}

/**
 * Create user select div(used in mailto input)
 *
 * @author                                 Yupeng Lee<leeyupeng@gmail.com>
 * @param     string   $InputElementID
 * @param     string   $Value
 * @param     string   $SelectListFunction
 * @return    object   $objResponse        the xajaxResponse object
 */
function xCreateSelectDiv($InputElementID, $Value, $SelectListFunction)
{
    $objResponse = new xajaxResponse();

    // Get args number.
    $ArgCount = func_num_args();
    $Value = sysAddSlash($Value);
    $SelectListFuntionParam = '"' . $Value . '"';

    // Get keys to sort by and put them to SortRule array.
    for($I = 3;$I < $ArgCount;$I ++)
    {
        $Param = func_get_arg($I);
        $Param = sysAddSlash($Param);
        $SelectListFuntionParam .= ',"' . $Param . '"';
    }
    eval('$SelectDiv = $SelectListFunction(' . $SelectListFuntionParam . ');');

    $TempKeyStr = $SelectDiv['Key'];
    $TempValueStr = $SelectDiv['Value'];

    $objResponse->addScript("var tempKeyArray = new Array({$TempKeyStr});var tempValueArray = new Array({$TempValueStr});");
    $objResponse->addScript("xajax.$('{$InputElementID}').selectDiv.optionKeyList = tempKeyArray;");
    $objResponse->addScript("xajax.$('{$InputElementID}').selectDiv.optionValueList = tempValueArray;");
    $objResponse->addScript("xajax.$('{$InputElementID}').selectDiv.createOptionDiv(tempKeyArray,tempValueArray);");

    return $objResponse;
}

/**
 * update project info
 *
 * @author                              Yupeng Lee<leeyupeng@gmail.com>
 * @param    array  $EditProjectForm    the info of form about edit project.
 * @return   object   $objResponse      the xajaxResponse object
 */
function xModle($EditProjectForm)
{
    global $_LANG;

    $objResponse = new xajaxResponse();
    xAssignActionMessage($objResponse, $_LANG['Message']['SucceedLogin'], "GoodNews");

    return $objResponse;
}

function xFillCustomedField($FieldSetID, $ProjectID, $Type, $ID)
{
    $objResponse = new xajaxResponse();
    $html = testGetCustomedFieldHtml($ProjectID, $Type, $ID);
    $objResponse->addAssign($FieldSetID, "innerHTML", $html);
    if(empty($html))
    {
        $objResponse->addAssign($FieldSetID, 'style.display', 'none');
    }
    else
    {
        $objResponse->addAssign($FieldSetID, 'style.display', 'block');
    }
    return $objResponse;
}

function testGetCustomedFieldHtml($ProjectID, $Type, $ID, $DisplayValue = false)
{
    global $_LANG;
    $ProjectInfo = dbGetRow('TestProject', null, 'ProjectID = ' . $ProjectID);
    $html = '<legend>' . $_LANG['CustomedField'] . '</legend>';
    if(empty($ProjectInfo['FieldSet']))
    {
        return null;
    }
    $xml = simplexml_load_string($ProjectInfo['FieldSet']);
    $fields = $xml->xpath('/fieldset/fields[@type="' . $Type . '"]/field');
    $fields = sysFieldXmlToArr($fields);
    $TableName = testGetFieldTable($Type, $ProjectInfo['ProjectID'], true);
    $FieldInfo = dbGetRow($TableName, '', "FieldID = $ID");
    foreach($fields as $field)
    {
        if($field['status'] != 'active')
        {
            continue;
        }
        $tmp = $field['name'];
        $name = 'CustomedFields[' . $field['name'] . ']';
        $html .= '<dl><dt>' . $field['text'] . '</dt>';
        $required = '';
        if($field['option'] != 'null')
        {
            $required = 'RequiredField';
        }
        $value = '';
        switch($field['type'])
        {
            case 'text':
            {
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlText($name, $FieldInfo["$tmp"], 'class=' . $required);
                break;
            }
            case 'textarea':
            {
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] .'" readonly="readonly" class="MyInput ReadOnlyField"') : htmlTextarea($name, $FieldInfo["$tmp"], 'class=' . $required);
                break;
            }
            case 'select':
            {
                $dataArr = explode(',', $field['value']);
                $dataArr = array_combine($dataArr, $dataArr);
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlSelect($dataArr, $name, null, $FieldInfo["$tmp"], 'class=' . $required);
                break;
            }
            case 'checkbox':
            {
                $dataArr = explode(',', $field['value']);
                $dataArr = array_combine($dataArr, $dataArr);
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlCheckBox($dataArr, $name, null, $FieldInfo["$tmp"], 'class=' . $required);
                break;
            }
            case 'mulit':
            {
                $dataArr = explode(',', $field['value']);
                $dataArr = array_combine($dataArr, $dataArr);
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlText($name, $FieldInfo["$tmp"], 'readonly="readonly" class="' . $required .'" onmouseup="initMulitDiv(\''. $name . '\', \'' . $field['value'] . '\')"');
                break;
            }
            case 'user':
            {
                $dataArr = testGetProjectUserList($ProjectID, true);
                $value = $DisplayValue ? htmlText($field['name'], $dataArr[$FieldInfo["$tmp"]], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlSelect($dataArr, $name, null, $FieldInfo["$tmp"], 'class=' . $required);
                break;
            }
            case 'date':
            {
                $value = $DisplayValue ? htmlText($field['name'], $FieldInfo["$tmp"], 'title="' . $FieldInfo["$tmp"] . '" readonly="readonly" class="MyInput ReadOnlyField"') : htmlText($name, $FieldInfo["$tmp"], 'class="'. $required . '" onfocus=addDate("'.$name.'")');
                break;
            }
            default:
            {
                break;
            }
        }
        $html .= '<dd>' . $value . '</dd></dl></div>';
    }
    return $html;
}


/*===================================xajax function end =============================*/

/**
 *
 * @author                 Yupeng Lee <leeyupeng@gmail.com>
 * @param   string $Module Bug,Case or Result
 */
function testSetCustomFields($Mode, $ProjectID = 0, $hasCustomField = false)
{
    global $_LANG;
    global $TPL;
    $ConstantFields = $_LANG[$Mode . "QueryField"];
    /* Create custom fields selected list */
    $DefaultFields = $_LANG['Default' . $Mode . 'QueryFields'];
    $FieldsToShow = array();
    if($ProjectID > 0 & $hasCustomField)
    {
        $ProjectInfo = dbGetRow('TestProject', '', "ProjectID='{$ProjectID}'");
        $FieldSet = $ProjectInfo['FieldSet'];
        if(!empty($FieldSet))
        {
            $xml = simplexml_load_string($FieldSet);
            $fields = $xml->xpath('/fieldset/fields[@type="'.$Mode.'"]/field');
            if($fields)
            {
                $fields = sysFieldXmlToArr($fields);
                $fieldArr = array();
                foreach($fields as $field)
                {
                    if($field['status'] != 'active')
                    {
                        continue;
                    }
                    $key = $field['name'];
                    $value = $field['text'];
                    $ConstantFields["$key"] = $value;
                    $_LANG[$Mode.'Fields']["$key"] = $value;
                }
            }
        }
    }
    if(!empty($_POST['FieldsToShow']))
    {
        $_SESSION[$Mode .'FieldsToShow'] = NULL;
        @setcookie($Mode . "CustomFields", $_POST['FieldsToShow'], time()+1209600, BF_COOKIE_PATH);
        jsGoTo($Mode . 'List.php');
        exit;
    }
    if($_SESSION[$Mode .'FieldsToShow'])
    {
        $CustomFields = explode(",", $_SESSION[$Mode .'FieldsToShow']);
        foreach($CustomFields as $FieldName)
        {
            if(!array_key_exists($FieldName, $ConstantFields))
            {
                continue;
            }
            $FieldsToShow[$FieldName] = $_LANG[$Mode  . "Fields"][$FieldName];
        }
    }
    elseif(!empty($_COOKIE[$Mode . "CustomFields"]))
    {
        $CustomFields = explode(",", $_COOKIE[$Mode . "CustomFields"]);
        foreach($CustomFields as $FieldName)
        {
            if(!array_key_exists($FieldName, $ConstantFields))
            {
                continue;
            }
            $FieldsToShow[$FieldName] = $_LANG[$Mode  . "Fields"][$FieldName];
        }
    }
    else
    {
        $FieldsToShow = $DefaultFields;
    }
    if(!$hasCustomField)
    {
        $arr = array_diff_key($FieldsToShow, $_LANG[$Mode  . "Fields"]);
        if(!empty($arr))
        {
            foreach($arr as $key)
            {
                unset($FieldsToShow[$key]);
                unset($ConstantFields[$key]);
            }
        }
    }

    $ACLAttrib = 'multiple="multiple" size="10" class="MultiSelect" style="width:150px"';
    $FieldsToSelectList = htmlSelect($ConstantFields, 'FieldsToSelectList', '', '', $ACLAttrib);
    $FieldsToShowList = htmlSelect($FieldsToShow, 'FieldsToShowList', '','', $ACLAttrib);

    $TPL->assign("FieldsToShow", $FieldsToShow);
    $TPL->assign("FieldsToSelectList", $FieldsToSelectList);
    $TPL->assign("FieldsToShowCount", count($FieldsToSelectList));
    $TPL->assign("FieldsToShowList", $FieldsToShowList);
    $TPL->assign("DefaultFieldsText",  '"' . join('","', $DefaultFields) . '"');
    $TPL->assign("DefaultFieldsValue", '"' . join('","', @array_keys($DefaultFields)) . '"');

    return $FieldsToShow;
}

/**
 *
 * @author                         Yupeng Lee <leeyupeng@gmail.com>
 * @param  string  $SearchUserName
 * @param  int     $ProjectID
 * @return string  $SelectDiv
 */
function selectDivProjectUserList($SearchUserName, $ProjectID)
{
    $SearchUserName = trim($SearchUserName);
    $SearchUserName = str_replace('\\', '\\\\', $SearchUserName);
    $SearchUserName = str_replace('.', '\\.', $SearchUserName);
    $SearchUserName = str_replace('[', '\\[', $SearchUserName);
    $SearchUserName = str_replace('{', '\\{', $SearchUserName);
    $SearchUserName = str_replace('+', '\\+', $SearchUserName);
    $SearchUserName = str_replace('(', '\\(', $SearchUserName);
    $SearchUserName = str_replace('|', '\\|', $SearchUserName);
    $SearchUserName = str_replace('?', '\\?', $SearchUserName);
    $SearchUserName = str_replace('*', '\\*', $SearchUserName);
    $SearchUserName = str_replace('"', '\\"', $SearchUserName);
    $SearchUserName = str_replace('$', '\\$', $SearchUserName);
    $SearchUserName = str_replace('^', '\\^', $SearchUserName);
    $SearchUserName = htmlspecialchars($SearchUserName);

    $ProjectUserList = testGetProjectUserList($ProjectID);
    $TempKeyArray = array();
    $TempValueArray = array();

    if($SearchUserName != '')
    {
        natcasesort($ProjectUserList);
        //uasort($ProjectUserList, 'testCmpPreAppendName');
        foreach($ProjectUserList as $UserName => $RealName)
        {
            if(preg_match("/".$SearchUserName."/i", $UserName) || preg_match("/".$SearchUserName."/i", $RealName))
            {
                $TempKeyArray[] = "'" . sysAddSlash($UserName) . "'";
                if(!preg_match("/\[" . sysAddSlash($UserName) . "\]/i", $RealName))
                {
                    $TempValueArray[] = "'" . sysAddSlash("{$RealName}[{$UserName}]") . "'";
                }
                else
                {
                    $TempValueArray[] = "'{$RealName}'";
                }
            }
        }
    }

    $SelectDiv = array('Key'=>join(',',$TempKeyArray), 'Value'=>join(',',$TempValueArray));
    return $SelectDiv;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getBugTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('BugInfo') , 'BugID,BugTitle', "BugID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    $IdArr = explode(',',$IdStr);
    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['BugID']] = $InfoTmp['BugTitle'];

    }
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getChangeTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ChangeInfo') , 'ChangeID,ChangeTitle', "ChangeID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    Rainy_Debug($ResultList,__FUNCTION__,__LINE__,__FILE__);
    $IdArr = explode(',',$IdStr);
    Rainy_Debug($IdArr,__FUNCTION__,__LINE__,__FILE__);

    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['ChangeID']] = $InfoTmp['ChangeTitle'];
    }
    Rainy_Debug($TitleInfoArr,__FUNCTION__,__LINE__,__FILE__);
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getReviewTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ReviewInfo') , 'ReviewID,ReviewTitle', "ReviewID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    $IdArr = explode(',',$IdStr);
    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['ReviewID']] = $InfoTmp['ReviewTitle'];

    }
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getReviewCommentTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ReviewCommentInfo') , 'ReviewCommentID,ReviewCommentTitle', "ReviewCommentID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    $IdArr = explode(',',$IdStr);
    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['ReviewCommentID']] = $InfoTmp['ReviewCommentTitle'];

    }
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getCaseTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('CaseInfo') , 'CaseID,CaseTitle', "CaseID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    $IdArr = explode(',',$IdStr);
    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['CaseID']] = $InfoTmp['CaseTitle'];

    }
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $IdStr
 * @return array  $TitleInfoArr
 */
function getResultTitleArr($IdStr)
{
    $IdStr = trimLastComma($IdStr);
    $sql =  dbGetListSql(dbGetPrefixTableNames('ResultInfo') , 'ResultID,ResultTitle', "ResultID in ($IdStr)");
    $ResultList = dbGetListBySql($sql);
    $IdArr = explode(',',$IdStr);
    $TitleInfoArr = array();
    for($j = 0;$j<count($ResultList);$j++)
    {
        $InfoTmp = $ResultList[$j];
        $TitleInfoArr[$InfoTmp['ResultID']] = $InfoTmp['ResultTitle'];

    }
    return $TitleInfoArr;
}

/**
 *
 * @author              xiaowen zhao <youzhao.zxw@taobao.com>
 * @param  string  $str
 * @return string  $str
 */
function trimLastComma($str)
{
    if(preg_match('/.*?,$/', $str))
    {
        $str = substr($str, 0, strlen($str)-1);
    }
    return $str;
}


function getPreNextId($IdInfoList,$IdFieldName,$ViewedId)
{
    if(count($IdInfoList)<=1)
    {
        $PreID = 0;
        $NextID = 0;
    }
    else
    {
        for($i=0;$i<count($IdInfoList);$i++)
        {
            if($IdInfoList[$i][$IdFieldName] == $ViewedId)
            {
                if(0 == $i)
                {
                    $PreID = 0;
                    $NextID = $IdInfoList[$i+1][$IdFieldName];
                }
                else if(count($IdInfoList)-1 == $i)
                {
                    $PreID = $IdInfoList[$i-1][$IdFieldName];
                    $NextID = 0;
                }
                else
                {
                    $PreID = $IdInfoList[$i-1][$IdFieldName];
                    $NextID = $IdInfoList[$i+1][$IdFieldName];

                }
                break;
            }
        }
    }
    return array($PreID,$NextID);
}
?>
